SQL INNER QUERY возвращает более одного значения в запросе UPDATE
У меня есть таблица, которую нужно обновить, используя записи другой таблицы, и я делаю это, чтобы перенести информацию из одной системы (базы данных) в другую. Сценарий немного сложен, но мне отчаянно нужна помощь :-s
Есть 3 таблицы - component
, scan
а также stage_link
составная часть
component_id stage_id
------------ --------
1 NULL
2 NULL
3 NULL
4 NULL
5 NULL
сканирование
scan_id component_id scanner_id date_scanned
------- ------------ ---------- -----------------------
1 1 scanner_a 2012-01-01 07:25:15.125
2 1 scanner_b 2012-01-02 08:14:05.456
3 2 scanner_a 2012-01-01 12:05:45.465
4 3 scanner_a 2012-01-01 19:45:12.536
5 1 scanner_c 2012-01-03 23:33:54.243
6 2 scanner_b 2012-01-02 11:59:12.545
stage_link
stage_link_id scanner_id stage_id
------- ---------- ----------
1 scanner_a 1
2 scanner_b 1
3 scanner_c 2
4 scanner_d 2
5 scanner_e 2
6 scanner_f 3
Мне необходимо update
стол component
а также set
поле stage_id
в соответствии с последним сканированием. Каждое сканирование выводит компонент на стадию в соответствии с задействованным сканером. Я написал следующий запрос для того, чтобы update
стол component
, но он выдает ошибку, говоря;
Subquery returned more than 1 value. This is not permitted when the subquery follows '='
Запрос есть;
UPDATE component
SET stage_id = (select stage_id
from(
select scn.scanner_id, sl.stage_id
from scan scn
INNER JOIN stage_link sl ON scn.scanner_id = sl.scanner_id
where scn.date_scanned = ( select temp_a.max_date
from ( SELECT x.component_id, MAX(x.date_scanned) as max_date
FROM scan x
where component_id = x.component_id
GROUP BY x.component_id
) as temp_a
where component_id = temp_a.component_id)
) as temp_b
)
Я работаю над MS SQL Server
и хочу разобраться, используя нет PHP
или любой другой язык.
В течение дня я пытался сделать эту работу, но все еще не получил способ сделать эту работу. Любая помощь будет высоко оценен!
Заранее большое спасибо:-)
3 ответа
Проверьте это, не используя коррелированные подзапросы:
UPDATE Com
SET stage_id = Temp4.stage_id
FROM dbo.component Com
INNER JOIN
(
SELECT Temp2.component_id ,SL.stage_id
FROM dbo.stage_link SL
INNER JOIN (
SELECT component_id ,scanner_id
FROM scan
WHERE date_scanned IN (
SELECT MaxScanDate
FROM
(
SELECT component_id , MAX(date_scanned) MaxScanDate
FROM scan
GROUP BY component_id
) Temp
)
) Temp2 ON Temp2.scanner_id = SL.scanner_id
) Temp4 ON Com.component_id = Temp4.component_id
Выход:
component_id stage_id
------------ -----------
1 2
2 1
3 1
4 NULL
5 NULL
Что ж, ваш подзапрос возвращает более одного значения. Один простой способ - выполнить агрегацию:
SET stage_id = (select max(stage_id)
. . .
Вероятная причина заключается в том, что за последнюю дату выполнено более одного сканирования. Поскольку вы можете выбрать только один, учитывая контекст, то достаточно MIN или MAX.
Тем не менее, я думаю, что настоящая причина в том, что у вас нет правильных псевдонимов, поскольку он коррелирует подзапрос. Я думаю, что эти строки:
where component_id = x.component_id
where component_id = temp_a.component_id
Должны включать псевдонимы, возможно, следующие:
where component.component_id = x.component_id
where component.component_id = temp_a.component_id
Если этого недостаточно, вам нужно объяснить, что вы хотите. Вы хотите, чтобы запрос возвращал случайное сканирование с самой последней даты? Хотите обновить компонент для всех проверок на самую последнюю дату?
Вам нужно исследовать это дальше. Попробуйте что-то вроде этого:
select scn.scanner_id, sl.stage_id, count(*)
from scan scn INNER JOIN
stage_link sl
ON scn.scanner_id = sl.scanner_id join
(SELECT x.component_id,
MAX(x.date_scanned) as max_date
FROM scan x
GROUP BY x.component_id
) cmax
on scn.component_id = cmax.component_id
where scn.date_scanned = cmax.maxdate
group by scn.scanner_id, sl.stage_id
order by count(*) desc
Для этого нужна была функция OLAP:
UPDATE Component SET Component.stage_id = Stage_Link.stage_id
FROM Component
JOIN (SELECT component_id, scanner_id,
ROW_NUMBER() OVER(PARTITION BY component_id
ORDER BY date_scanned DESC) rownum
FROM Scan) Scan
ON Scan.component_id = Component.component_id
AND Scan.rownum = 1
JOIN Stage_Link
ON Stage_Link.scanner_id = Scan.scanner_id
WHERE Component.stage_id IS NULL
Который генерирует результирующий набор:
Component
component_id stage_id
========================
1 2
2 1
3 1
4 null
5 null
(У меня также есть рабочий пример SQL Fiddle.)