Функциональность, подобная массиву, в SQL Server 2008 - PullRequest
1 голос
/ 01 октября 2010

Я хочу прочитать EmpID в EMP Таблица основана на некоторых условиях.Для каждого EmpID мне нужно выполнить какую-то операцию в другой таблице.Как я могу прочитать одно значение EmpID за раз.

Заранее спасибо

Ответы [ 5 ]

1 голос
/ 01 октября 2010
UPDATE otherTable... 
WHERE table2.EmpID IN (SELECT EMP.EmpID FROM EMP WHERE ...)
0 голосов
/ 01 октября 2010

стараться никогда не зацикливаться, работать с наборами данных.

Вы можете вставлять, обновлять, удалять несколько строк одновременно. здесь в качестве примера вставка нескольких строк:

INSERT INTO YourTable
        (col1, col2, col3, col4)
    SELECT
        cola, colb+Colz, colc, @X
        FROM ....
            LEFT OUTER JOIN ...
        WHERE...

вы даже можете вставить в несколько таблиц в одном выражении:

INSERT INTO YourTable
        (col1, col2, col3, col4)
        OUTPUT INSERTED.PK, Inserted.Col2
            INTO OtherTable (ColA, ColB)
    SELECT
        cola, colb+Colz, colc, @X
        FROM ....
            LEFT OUTER JOIN ...
        WHERE...

Когда вы смотрите на цикл, посмотрите, что он сделал внутри. Если он просто вставляет / удаляет / обновляет, переписать, чтобы использовать отдельные команды. Если есть IF, посмотрите, могут ли они быть операторами CASE или условиями WHERE для вставок / удалений / обновлений. Если это так, удалите цикл и используйте команды set.

Я взял циклы и заменил их командами на основе набора и сократил время выполнения с минут до нескольких секунд. Я взял процедуры со многими вложенными циклами и вызовами процедур и сохранил циклы (было невозможно использовать только вставки / удаления / обновления), но я убрал курсор, и увидел меньше блокировок / блокировок и значительное повышение производительности. Вот два метода зацикливания, которые лучше, чем зацикливание курсора ...

если вам нужно выполнить цикл, над набором сделайте что-то вроде этого:

--this looks up each row for every iteration
DECLARE @msg VARCHAR(250)
DECLARE @hostname sysname

--first select of currsor free loop
SELECT @hostname= min(RTRIM(hostname))
    FROM  master.dbo.sysprocesses (NOLOCK)
    WHERE  hostname <> ''

WHILE @hostname is not null
BEGIN
    --just some example of some odd task that requires a loop
    set @msg='exec master.dbo.xp_cmdshell "net send ' 
        + RTRIM(@hostname) + ' '
        + 'testing  "'
    print @msg
    --EXEC (@msg) --<<will not actually send the messages

    --next select of cursor free loop
    SELECT @hostname= min(RTRIM(hostname))
        FROM master.dbo.sysprocesses (NOLOCK)
        WHERE  hostname <> ''
        and hostname > @hostname
END

если у вас есть разумный набор предметов (не 100 000) для зацикливания, вы можете сделать это:

--this will capture each Key to loop over
DECLARE @msg VARCHAR(250)
DECLARE @From   int
DECLARE @To     int
CREATE TABLE #Rows  --use a table @variable depending on the number of rows to handle
(
     RowID     int not null primary key identity(1,1)
    ,hostname  varchar(100)
)

INSERT INTO #Rows
SELECT DISTINCT hostname
    FROM  master.dbo.sysprocesses (NOLOCK)
    WHERE  hostname <> ''
SELECT @From=0,@To=@@ROWCOUNT

WHILE @From<@To
BEGIN
    SET @From=@From+1

    --just some example of some odd task that requires a loop
    SELECT @msg='exec master.dbo.xp_cmdshell "net send ' 
        + RTRIM(hostname) + ' '
        + 'testing  "'
        FROM #Rows 
        WHERE RowID=@From
    print @msg
    --EXEC (@msg) --<<will not actually send the messages
END
0 голосов
/ 01 октября 2010

Исходя из Ответа DanDan , T-SQL позволяет вам выполнять объединение в предложении FROM оператора UPDATE (я не могу вспомнить, является ли это ANSI или нет). EG

UPDATE 
    OtherTable
SET 
    Auditing = Employees.EmployeeName
FROM 
    OtherTable
    INNER JOIN 
        Employees ON OtherTable.EmpId = Employees.EmpId
WHERE
    Employees.DateStarted > '2010-09-01'
0 голосов
/ 01 октября 2010

Использование подхода на основе множеств к логике SQL всегда является предпочтительным подходом. В этом смысле ответ DanDan является приемлемым. В качестве альтернативы вы можете использовать курсоры SQL. Несмотря на большой ресурс, они позволят вам перебрать множество и применить логику к каждой строке.

DECLARE @EMPID char(11)

DECLARE c1 CURSOR READ_ONLY
FOR
SELECT EmpID
FROM EMP

ГДЕ * some_clause *

OPEN c1

FETCH NEXT FROM c1
INTO @EMPID

WHILE @@FETCH_STATUS = 0
BEGIN

    PRINT @EMPID

    FETCH NEXT FROM c1
    INTO @EMPID

END

CLOSE c1
DEALLOCATE c1
0 голосов
/ 01 октября 2010

Как правило, вам следует избегать процедурного кода в SQL, но если вам действительно нужно, используйте CURSOR:

DECLARE myCursor CURSOR FAST_FORWARD
FOR
    SELECT    --your SQL query, a regular SQL query.
        field1,
        field2
    FROM 
        table

OPEN myCursor;
FETCH NEXT FROM myCursor 
INTO 
    @var1, --must be pre-declared, of the same types as field1
    @var2

WHILE (@@FETCH_STATUS = 0) 
BEGIN


    --your code use @var1, @var2. Perform queries, do whatever you like. 
    --It will loop through every row fetched by the query in the beginning of the code, and perform this.


    FETCH NEXT FROM myCursor --do this exactly as before the WHILE loop
    INTO 
        @var1,
        @var2
END
CLOSE myCursor
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...