Обновление и объединение нескольких строк, какое значение строки используется? - PullRequest
24 голосов
/ 29 февраля 2012

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

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

Ответы [ 5 ]

18 голосов
/ 29 февраля 2012

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

Если вы после определенной строки, скажем, последней, вы можете использовать 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
7 голосов
/ 29 февраля 2012

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

2 голосов
/ 16 июля 2013

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

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

;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.
2 голосов
/ 29 февраля 2012

Вот что я придумал, используя 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, чтобы убедиться, что вы знаете, какую ценность вы собираетесь выбрать.

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

0 голосов
/ 01 апреля 2017

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

    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, и вы получите обратное. Я согласен с приведенными выше постерами ... очень странно, что эта операция не выдает сообщение об ошибке, поскольку полностью скрыто , что эта операция игнорирует вторичные значения

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...