#sql #sql-server #loops
#sql #sql-сервер #циклы
Вопрос:
У меня есть таблица sdata
, и в ней 35 столбцов ( id
, name
, TRx1
, TRx2
, TRx3
, TRx4
,…, TRx30
, city
, score
, total
)
Я хочу извлекать данные из TRx1,...TRx30
столбцов.
Могу ли я использовать цикл здесь?
Я выполнил следующий код:
DECLARE @flag INT
DECLARE @sel varchar(255)
DECLARE @frm varchar(255)
SET @flag = 1;
SET @sel = 'select TRx';
SET @frm = ' from sdata';
exec(@sel
(WHILE @flag <=5
@flag
SET @flag = @flag 1)
@frm)
Что я делаю не так? И как я могу это решить?
Комментарии:
1. Копирование / вставка и изменение имен столбцов было бы в миллион раз быстрее (и менее сложным / подверженным ошибкам), чем написание
while
цикла для построения динамического запроса..2. не используйте цикл в SQL. никогда. не делайте этого. SQL — это не циклы.
3. Я не понимаю, почему люди ненавидят цикл while. Это
loop
просто для генерации строки, в которой нет ничего плохого…. Когда вы обрабатываете данные запись за записью (ie)RBAR
, тогда вам нужно беспокоиться, но этот цикл в порядке.4. @Prdp — Дело не в том, что я ненавижу циклы, проблема в том, что циклы работают медленно. Циклы работают плохо — они «работают» в SQL, но не очень хорошо. Это означает (в качестве примера), что там, где я работаю, около 2000 запросов в час, и если бы они были реализованы как циклы, они никогда бы не завершились и не привели к сбою всей системы. SQL разработан так, чтобы не использовать циклы — хотя вы можете их использовать, но это ДЕЙСТВИТЕЛЬНО ОЧЕНЬ плохая идея. Кроме того, вы ничего не можете сделать с циклом в SQL, вы также не можете обойтись без цикла и быстрее, так зачем их использовать?
5. Не используйте это просто для сохранения нажатий клавиш, потому что это имеет большое значение в SQL, является ли ваш запрос статическим или динамическим. Если
5
в вашем примере выше не будет переменной или параметром, не беспокойтесь об этом и просто выпишите запрос полностью, каким бы неуклюжим он ни выглядел. Также рассмотрите возможность простого извлечения всех столбцов и использования клиентского фильтра. Это может быть или не быть подходящим с точки зрения производительности, но это, безусловно, упрощает работу с SQL.
Ответ №1:
Если ваше имя таблицы sdata, этот код должен работать для вас:
-- Grab the names of all the remaining columns
DECLARE @sql nvarchar(MAX);
DECLARE @columns nvarchar(MAX);
SELECT @columns = STUFF ( ( SELECT N'], [' name
FROM sys.columns
WHERE object_id = (select top 1 object_id FROM sys.objects where name = 'sdata')
AND name LIKE 'TRx%' -- To limit which columns
ORDER BY column_id
FOR XML PATH('')), 1, 2, '') ']';
PRINT @columns
SELECT @sql = 'SELECT ' @columns ' FROM sdata';
PRINT @sql;
EXEC (@sql);
Обратите внимание, что я включил операторы печати, чтобы вы могли видеть, что происходит. Возможно, вы захотите прокомментировать EXEC во время тестирования.
Комментарии:
1. Использование
QUOTENAME
для экранирования столбцов немного более надежно (хотя, по общему признанию, вы мазохист, если используете]
в своих именах столбцов).SELECT QUOTENAME(name) ','
и удалите финал,
сREVERSE(STUFF(REVERSE((...)), 1, 1, ''))
помощью .2. Это отсутствует
AND name LIKE 'TRx%'
, если нам нужны только эти столбцы. (Одной из сильных сторон этого подхода является возможность выбора из реальных столбцов на основе любых критериев, которые нам нравятся, так что вы можете также показать это.)3. Правильно… Я хотел предоставить более «общий» шаблон, который можно было бы настраивать, а также быть максимально «понятным». Я обновлю фрагмент, чтобы он был более понятным. Спасибо.
Ответ №2:
Это было бы намного проще сделать, просто скопировав / вставив имена столбцов и изменив их на правильные. Однако, если вы должны сделать это таким образом, я вообще не советую использовать цикл. Этот метод использует таблицу подсчета для генерации столбцов, которые вы хотите выбрать (в этом примере столбцы 1
сквозные 30
, но это можно изменить), затем генерирует динамическую инструкцию SQL для выполнения с SData
таблицей:
Declare @From Int = 1,
@To Int = 30,
@Sql NVarchar (Max)
Declare @Columns Table (Col Varchar (255))
;With Nums As
(
Select *
From (Values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) As V(N)
), Tally As
(
Select Row_Number() Over (Order By (Select Null)) As N
From Nums A --10
Cross Join Nums B --100
Cross Join Nums C --1000
)
Insert @Columns
Select 'TRx' Cast(N As Varchar)
From Tally
Where N Between @From And @To
;With Cols As
(
Select (
Select QuoteName(Col) ',' As [text()]
From @Columns
For Xml Path ('')
) As Cols
)
Select @Sql = 'Select ' Left(Cols, Len(Cols) - 1) ' From SData'
From Cols
--Select @Sql
Execute (@Sql)
Примечание: --Select @Sql
раздел предназначен для предварительного просмотра сгенерированного запроса перед его выполнением.
Комментарии:
1. Спасибо. Код работает идеально, но его трудно понять, поскольку я новичок в sql.
Ответ №3:
Вы можете выбрать имена столбцов следующим образом:
SELECT column_name
FROM information_schema.columns
WHERE table_name = 'my name here'