Подтвердить что ты не робот

Обновление и объединение нескольких строк, какое значение строки используется?

Скажем, у меня есть следующая инструкция, и внутреннее соединение приводит к 3 строкам, где a.Id = b.Id, но каждая из трех строк имеет разные значения b.Value. Поскольку обновляется только одна строка из таблицы A, какое из трех значений используется в обновлении?

UPDATE a
SET a.Value = b.Value
FROM tableA AS a
INNER JOIN tableB as b 
ON a.Id = b.Id
4b9b3361

Ответ 1

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

Если вы после определенной строки, скажем, последней, вы можете использовать apply, например:

UPDATE  a
SET     a.Value = b.Value
FROM    tableA AS a
CROSS APPLY
        (
        select  top 1 *
        from    tableB as b
        where   b.id = a.id
        order by
                DateColumn desc
        ) as b

Ответ 2

Обычно в этом сценарии вы получаете первую строку, которая отображается в порядке физического индекса в таблице. На практике вы должны рассматривать это как недетерминированное и включать то, что сужает ваш результат до одной строки.

Ответ 3

Вот что я придумал с помощью SQL Server 2008

--drop table #b
--drop table #a
select 1 as id, 2 as value
into #a

select 1 as id, 5 as value
into #b

insert into #b
select 1, 3

insert into #b
select 1, 6

select * from #a
select * from #b

UPDATE #a 
SET #a.Value = #b.Value
FROM #a
INNER JOIN #b 
ON #a.Id = #b.Id

Кажется, что он использует верхнее значение базового выбора каждый раз (строка 1 выбора * из #b). Таким образом, возможно, это зависит от индексации. Однако я бы не стал полагаться на реализацию, установленную SQL, поскольку это имеет возможность изменения. Вместо этого я бы предложил использовать решение, представленное Andomar, чтобы убедиться, что вы знаете, какое значение вы собираетесь выбрать.

Короче говоря, не доверяйте реализации по умолчанию, создайте свой собственный. Но это был интересный академический вопрос:)

Ответ 4

Наилучшим вариантом в моем случае для обновления нескольких записей является использование запроса на слияние (поддерживается SQL Server 2008), в этом запросе вы полностью контролируете то, что вы обновляете. Также вы можете использовать выходной запрос для дальнейшей обработки.

Пример: Без предложения вывода (только обновление)

;WITH cteB AS
( SELECT Id, Col1, Col2, Col3  
  FROM B WHERE Id > 10  ---- Select Multiple records
)
MERGE A
USING cteB
ON(A.Id = cteB.Id) -- Update condition
WHEN MATCHED THEN UPDATE
SET  
A.Col1 = cteB.Col1,  --Note: Update condition i.e; A.Id = cteB.Id cant appear here   again.
A.Col2 = cteB.Col2,
A.Col3 = cteB.Col3;

Пример: с предложением OputPut

CREATE TABLE #TempOutPutTable
  {
  PkId INT NOT NULL,
  Col1 VARCHAR(50),
  Col2 VARCHAR(50)
  }

;WITH cteB AS
( SELECT Id, Col1, Col2, Col3
FROM B WHERE Id > 10
)
MERGE A
USING cteB
ON(A.Id = cteB.Id)
WHEN MATCHED THEN UPDATE
SET  
A.Col1 = cteB.Col1, 
A.Col2 = cteB.Col2,
A.Col3 = cteB.Col3
OUTPUT 
 INSERTED.Id, cteB.Col1, A.Col2 INTO #TempOutPutTable;

--Do what ever you want with the data in temporary table
SELECT * FROM #TempOutPutTable; -- you can check here which records are updated.

Ответ 5

Да, я придумал аналогичный эксперимент с Джастином Пихони:

    IF OBJECT_ID('tempdb..#test') IS NOT NULL DROP TABLE #test ;
SELECT 
1 AS Name, 0 AS value 
INTO #test

IF OBJECT_ID('tempdb..#compare') IS NOT NULL DROP TABLE #compare ;
SELECT 1 AS name, 1 AS value
INTO #compare
INSERT INTO #compare
SELECT 1 AS name, 0 AS value;

SELECT * FROM #test
SELECT * FROM #compare

UPDATE t
SET t.value = c.value
FROM #test t
INNER JOIN #compare c
    ON t.Name = c.name

Принимает верхнюю строку в таблице сравнения справа. Вы можете изменить значения # compare.value на 0 и 1, и вы получите обратное. Я согласен с плакатами выше... очень странно, что эта операция не выдает сообщение об ошибке, поскольку она полностью скрыта, что эта операция IGNORES вторичных значений