2013-04-04 2 views
2

По сути то, что я хочу сделать в псевдокоде:Для каждого запроса типа SQL

FOR EACH pig_id IN (SELECT pig_id FROM farm AS f) 
BEGIN 
-- Do something funky with the f.pig_id, for example 
    SELECT bacon, ham, pork, (face + guts + brains + testicles) AS 'sausage' 
    FROM farm 
    WHERE pig_id = f.pig_id 
END 

Реально внутренняя часть цикла является более сложным, но это простое ЗЕЬЕСТ демонстрирует необходимость использования f.pig_id внутри цикла ДЛЯ КАЖДОГО pig_id в ферме ТАБЛИЦА. Я посмотрел на решение CREATE TRIGGER, но я надеялся на что-то более простое. Я знаю, что это неэффективный запрос, но проект требовал простоты и легко читаемых человеком запросов для нетехнических людей.

EDIT: Он используется на небольшом наборе данных, поэтому человеческая читаемость является приоритетом по эффективности.

+2

Вы пытаетесь сделать что-то неэффективное. Возможно, вам повезло вставить строки в временную таблицу, при необходимости обновив их, а затем запросив временную таблицу. –

+2

Это иногда называется «RBAR» Row By Agonizing Row. Это НЕ вы, как вы хотите начать кодирование TSQL. – granadaCoder

+1

Я не совсем уверен, почему JOIN (или JOINS) не хватит - когда вы видите такой код, как правило, это связано с непониманием SQL и множеством! – Jamie

ответ

2

Если pig_id уникальный столбец (например. с типом данных Int) можно использовать цикл без CURSOR

DECLARE @id int = (SELECT MIN(pig_id) FROM farm) 
WHILE (@id IS NOT NULL) 
BEGIN 
    SELECT bacon, ham, pork, (face + guts + brains + testicles) AS 'sausage' 
    FROM farm 
    WHERE pig_id = @id 

    SELECT @id = MIN(pig_id) FROM farm WHERE pig_id > @Id 
END 

ИЛИ

DECLARE @id int = 0 
WHILE 1 = 1 
BEGIN 
    SELECT @id = (select min(pig_id) from farm where pig_id > @id)  

    IF @id IS NULL 
    BREAK 
    ELSE 

    SELECT bacon, ham, pork, (face + guts + brains + testicles) AS 'sausage' 
    FROM farm 
    WHERE pig_id = @id 
    CONTINUE 
END 
+0

Cheers mate, это, казалось, самое элегантное решение. Спасибо за вашу помощь. – Gregology

+0

Добро пожаловать. –

2

Я думаю, что вы ищете CURSOR

Здесь link to MSDN examples, есть просто один весь путь на bottome.

+1

Курсоры злы, и их следует использовать только в последней, последней, последней, последней инстанции. – granadaCoder

+2

@granadaCoder Я не согласен, но иногда необходимо зло, не зная специфику приложения, не может быть другого способа ... – Borik

+1

Возможно, это единственный способ. Но за последние 10 лет с тех пор, как я выпустил указ «без курсора» (в моей группе), у меня была только одна ситуация, когда код с привязкой не мог быть написан. Ты его не предупредил. Вы только что дали ему дину @ клеща, с которым можно отправиться на рыбалку. Ака, можно ловить рыбу с помощью клеща dyn @, но я не рекомендую его. – granadaCoder

1

RBAR = BAD.

https://www.simple-talk.com/sql/t-sql-programming/rbar--row-by-agonizing-row/

Комплект на основе хорошо!

.............................

Я создал ANTI пример здесь:

http://granadacoder.wordpress.com/2008/07/24/cursors-setbased-and-scalar-udf/

Простой пример: я показываю вам, как использовать курсор, но затем я покажу вам, как НЕ использовать курсор для решения одной и той же проблемы.

Пожалуйста, пожалуйста, избегайте курсоров.

1

Если вам нужно сделать что-то сложное со значениями из первого запроса, вы можете использовать курсор.

Пример:

DECLARE @pig int 
DECLARE db_cursor CURSOR FOR 
SELECT pig_id FROM farm AS f 

OPEN db_cursor 
FETCH NEXT FROM db_cursor INTO @pig 

WHILE @@FETCH_STATUS = 0 
BEGIN 
     --Do your thing here.... 

     FETCH NEXT FROM db_cursor INTO @pig 
END 

CLOSE db_cursor 
DEALLOCATE db_cursor 
1

Как уже упоминалось, курсор должен делать то, что вы хотите, вот простой пример:

DECLARE @valueHolder INT 

DECLARE myCursor CURSOR FOR SELECT ID FROM MyTable 
OPEN myCursor 

FETCH NEXT FROM myCursor INTO @valueHolder 

WHILE @@FETCH_STATUS = 0 
BEGIN 
    PRINT @valueHolder 

    FETCH NEXT FROM myCursor INTO @valueHolder 
END 

CLOSE myCursor; 
DEALLOCATE myCursor; 
1

без использования курсора вы можете просто использовать счетчик и WHILE цикл:

Схема:

CREATE TABLE #Pig 
(
PigId INT 
) 
INSERT INTO #Pig VALUES 
(1), 
(3), 
(6), 
(10) 

CREATE TABLE #Farm 
(
PigId INT, 
Name VARCHAR(20) 
) 
INSERT INTO #Farm VALUES 
(1,'michaeljackson'), 
(1,'jim'), 
(3,'jill'), 
(3,'j') 

Сценарий:

SELECT PigId, 
     rn = ROW_NUMBER() OVER (ORDER BY PigId) 
INTO #PigRows 
FROM #Pig 


DECLARE @max INT = (SELECT MAX(rn) FROM #PigRows) 

DECLARE @counter INT = 1 
WHILE @counter <= @max 
BEGIN 

    SELECT Name 
    FROM #Farm 
    WHERE PigId = @counter 

    SET @counter = @counter + 1 
END 
Смежные вопросы