Как написать foreach в SQL Server?
Я пытаюсь добиться чего-то по строкам for-each, где я бы хотел взять идентификаторы возвращаемого оператора select и использовать каждый из них.
DECLARE @i int
DECLARE @PractitionerId int
DECLARE @numrows int
DECLARE @Practitioner TABLE (
idx smallint Primary Key IDENTITY(1,1)
, PractitionerId int
)
INSERT @Practitioner
SELECT distinct PractitionerId FROM Practitioner
SET @i = 1
SET @numrows = (SELECT COUNT(*) FROM Practitioner)
IF @numrows > 0
WHILE (@i <= (SELECT MAX(idx) FROM Practitioner))
BEGIN
SET @PractitionerId = (SELECT PractitionerId FROM @Practitioner WHERE idx = @i)
--Do something with Id here
PRINT @PractitionerId
SET @i = @i + 1
END
В настоящий момент у меня есть что-то похожее на выше, но я получаю ошибку:
Недопустимое имя столбца 'idx'.
Может кто-нибудь
Ответы
Ответ 1
Кажется, вы хотите использовать CURSOR
. Хотя в большинстве случаев лучше всего использовать решение на основе набора, есть несколько раз, когда CURSOR
является лучшим решением. Не зная больше о вашей реальной проблеме, мы не можем вам больше помочь:
DECLARE @PractitionerId int
DECLARE MY_CURSOR CURSOR
LOCAL STATIC READ_ONLY FORWARD_ONLY
FOR
SELECT DISTINCT PractitionerId
FROM Practitioner
OPEN MY_CURSOR
FETCH NEXT FROM MY_CURSOR INTO @PractitionerId
WHILE @@FETCH_STATUS = 0
BEGIN
--Do something with Id here
PRINT @PractitionerId
FETCH NEXT FROM MY_CURSOR INTO @PractitionerId
END
CLOSE MY_CURSOR
DEALLOCATE MY_CURSOR
Ответ 2
Предположим, что столбец PractitionerId является уникальным, тогда вы можете использовать следующий цикл
DECLARE @PractitionerId int = 0
WHILE(1 = 1)
BEGIN
SELECT @PractitionerId = MIN(PractitionerId)
FROM dbo.Practitioner WHERE PractitionerId > @PractitionerId
IF @PractitionerId IS NULL BREAK
SELECT @PractitionerId
END
Ответ 3
Ваш счетчик выбора и выберите max должны быть из вашей переменной таблицы вместо фактической таблицы
DECLARE @i int
DECLARE @PractitionerId int
DECLARE @numrows int
DECLARE @Practitioner TABLE (
idx smallint Primary Key IDENTITY(1,1)
, PractitionerId int
)
INSERT @Practitioner
SELECT distinct PractitionerId FROM Practitioner
SET @i = 1
SET @numrows = (SELECT COUNT(*) FROM @Practitioner)
IF @numrows > 0
WHILE (@i <= (SELECT MAX(idx) FROM @Practitioner))
BEGIN
SET @PractitionerId = (SELECT PractitionerId FROM @Practitioner WHERE idx = @i)
--Do something with Id here
PRINT @PractitionerId
SET @i = @i + 1
END
Ответ 4
Я бы сказал, что все, вероятно, работает, за исключением того, что столбец idx
фактически не существует в выбранной вами таблице. Возможно, вы хотели выбрать из @Practitioner
:
WHILE (@i <= (SELECT MAX(idx) FROM @Practitioner))
потому что это определено в коде выше:
DECLARE @Practitioner TABLE (
idx smallint Primary Key IDENTITY(1,1)
, PractitionerId int
)
Ответ 5
Это обычно (почти всегда) работает лучше, чем курсор и проще:
DECLARE @PractitionerList TABLE(PracticionerID INT)
DECLARE @PractitionerID INT
INSERT @PractitionerList(PracticionerID)
SELECT PracticionerID
FROM Practitioner
WHILE(1 = 1)
BEGIN
SET @PracticionerID = NULL
SELECT TOP(1) @PracticionerID = PracticionerID
FROM @PractitionerList
IF @PracticionerID IS NULL
BREAK
PRINT 'DO STUFF'
DELETE TOP(1) FROM @PractitionerList
END
Ответ 6
В вашей версии неправильная строка:
WHILE (@i <= (SELECT MAX(idx) FROM @Practitioner))
(Отсутствует @)
Может возникнуть идея изменить ваше соглашение об именах, чтобы таблицы были более разными.
Ответ 7
Хотя курсоры обычно считаются ужасным злом, я считаю, что это случай для курсора FAST_FORWARD - ближайшая вещь, которую вы можете получить FOREACH в TSQL.
Ответ 8
Вам нужен курсор SQL Server.
Это ссылка MSDN. Для простого примера см. this.
Ответ 9
Я придумал очень эффективный (я думаю) читабельный способ сделать это.
1. create a temp table and put the records you want to iterate in there
2. use WHILE @@ROWCOUNT <> 0 to do the iterating
3. to get one row at a time do, SELECT TOP 1 <fieldnames>
b. save the unique ID for that row in a variable
4. Do Stuff, then delete the row from the temp table based on the ID saved at step 3b.
Здесь код. Извините, вместо имен в вопросе используются мои имена переменных.
declare @tempPFRunStops TABLE (ProformaRunStopsID int,ProformaRunMasterID int, CompanyLocationID int, StopSequence int );
INSERT @tempPFRunStops (ProformaRunStopsID,ProformaRunMasterID, CompanyLocationID, StopSequence)
SELECT ProformaRunStopsID, ProformaRunMasterID, CompanyLocationID, StopSequence from ProformaRunStops
WHERE ProformaRunMasterID IN ( SELECT ProformaRunMasterID FROM ProformaRunMaster WHERE ProformaId = 15 )
-- SELECT * FROM @tempPFRunStops
WHILE @@ROWCOUNT <> 0 -- << I dont know how this works
BEGIN
SELECT TOP 1 * FROM @tempPFRunStops
-- I could have put the unique ID into a variable here
SELECT 'Ha' -- Do Stuff
DELETE @tempPFRunStops WHERE ProformaRunStopsID = (SELECT TOP 1 ProformaRunStopsID FROM @tempPFRunStops)
END
Ответ 10
Вот одно из лучших решений.
DECLARE @i int
DECLARE @curren_val int
DECLARE @numrows int
create table #Practitioner (idx int IDENTITY(1,1), PractitionerId int)
INSERT INTO #Practitioner (PractitionerId) values (10),(20),(30)
SET @i = 1
SET @numrows = (SELECT COUNT(*) FROM #Practitioner)
IF @numrows > 0
WHILE (@i <= (SELECT MAX(idx) FROM #Practitioner))
BEGIN
SET @curren_val = (SELECT PractitionerId FROM #Practitioner WHERE idx = @i)
--Do something with Id here
PRINT @curren_val
SET @i = @i + 1
END
Здесь я добавил некоторые значения в таблицу, потому что изначально она пуста.
Мы можем получить доступ или сделать что угодно в теле цикла, и мы можем получить доступ к idx, определив его внутри определения таблицы.
BEGIN
SET @curren_val = (SELECT PractitionerId FROM #Practitioner WHERE idx = @i)
--Do something with Id here
PRINT @curren_val
SET @i = @i + 1
END