我有两个表,Table_1
和Table_2
。
我正在使用此SQL语句来计算Info_Data
中Table_1
列中特定数据的出现次数。在其当前的硬编码形式中,它返回值9
SELECT Staff_No, Info_Data, COUNT(*) cCount
FROM Staff_Manager.dbo.Staff_Time_TBL
WHERE Staff_No = 3201 AND Date_Data BETWEEN '2016/6/1' AND '2016/7/1' AND Info_Data = 'Data_1'
GROUP BY Staff_No, Info_Data
然后我有另一个SQL语句检查Table_2
中是否存在行,如果不存在,则插入行并更新数据。如果是,只需更新数据。
IF EXISTS (SELECT * FROM Staff_Manager.dbo.Staff_Count_TBL WHERE Staff_No = 3201 AND Year_D = 2016 AND Month_D = 6 AND Column_Index = 1)
BEGIN
UPDATE Staff_Manager.dbo.Staff_Count_TBL
SET Column_Value = 9
WHERE Staff_No = 3201 AND Year_D = 2016 AND Month_D = 6 AND Column_Index = 1
END
ELSE
BEGIN
INSERT INTO Staff_Manager.dbo.Staff_Count_TBL (Staff_No, Year_D, Month_D, Column_Index, Column_Value)
VALUES (3201, 2016, 6, 1, 9)
END
这些陈述都是按照它们应有的方式运作的。
但我找不到合并这两种陈述的方法,我试过JOIN
,MERGE
没有运气。
由于第一个语句返回的值为9
,我想替换此行9
上的硬编码SET Column_Value = 9
和Column_Value
列值9
在这一行VALUES (3201, 2016, 6, 1, 9)
上有第一个陈述的结果
这显然是不正确的,但要说明我想要做的事情。
IF EXISTS (SELECT * FROM Staff_Manager.dbo.Staff_Count_TBL WHERE Staff_No = 3201 AND Year_D = 2016 AND Month_D = 6 AND Column_Index = 1)
BEGIN
UPDATE Staff_Manager.dbo.Staff_Count_TBL
SET Column_Value = SELECT Staff_No, Info_Data, COUNT(*) cCount
FROM Staff_Manager.dbo.Staff_Time_TBL
WHERE Staff_No = 3201 AND Date_Data BETWEEN '2016/6/1' AND '2016/7/1' AND Info_Data = 'Data_1'
GROUP BY Staff_No, Info_Data
WHERE Staff_No = 3201 AND Year_D = 2016 AND Month_D = 6 AND Column_Index = 1
END
ELSE
BEGIN
INSERT INTO Staff_Manager.dbo.Staff_Count_TBL (Staff_No, Year_D, Month_D, Column_Index, Column_Value)
VALUES (3201, 2016, 6, 1, SELECT Staff_No, Info_Data, COUNT(*) cCount
FROM Staff_Manager.dbo.Staff_Time_TBL
WHERE Staff_No = 3201 AND Date_Data BETWEEN '2016/6/1' AND '2016/7/1' AND Info_Data = 'Data_1'
GROUP BY Staff_No, Info_Data)
END
答案 0 :(得分:3)
您的第一个查询会返回多个列,您无法使用它来更新或插入单个列。相反,让它只返回count()
并尝试
UPDATE Staff_Manager.dbo.Staff_Count_TBL
SET Column_Value = (
SELECT COUNT(*)
FROM Staff_Manager.dbo.Staff_Time_TBL
WHERE Staff_No = 3201 AND Date_Data BETWEEN '2016/6/1' AND '2016/7/1' AND Info_Data = 'Data_1'
GROUP BY Staff_No, Info_Data
)
WHERE Staff_No = 3201 AND Year_D = 2016 AND Month_D = 6 AND Column_Index = 1
和
INSERT INTO Staff_Manager.dbo.Staff_Count_TBL
(Staff_No, Year_D, Month_D, Column_Index, Column_Value)
SELECT 3201, 2016, 6, 1, COUNT(*)
FROM Staff_Manager.dbo.Staff_Time_TBL
WHERE Staff_No = 3201 AND Date_Data BETWEEN '2016/6/1' AND '2016/7/1' AND Info_Data = 'Data_1'
GROUP BY Staff_No, Info_Data
如您所见,在INSERT中没有VALUES构造,请阅读http://www.w3schools.com/sql/sql_insert_into_select.asp以获取更多详细信息。另请参阅How do I UPDATE from a SELECT in SQL Server?。
P.S。单个查询不需要使用BEGIN / END,可以跳过它们。
答案 1 :(得分:1)
接受的答案中两个陈述中的冗余困扰我,即需要在至少两个地方改变一个业务规则。
所以这是我尝试编写等效的MERGE
语句(相信你可以在这里看到表值参数的可能性):
WITH Params AS
(
SELECT *
FROM ( VALUES ( 3201, 2016, 6, 1 ) )
AS T ( Staff_No, Year_D, Month_D, Column_Index )
),
ParamsWithCount AS
(
SELECT p.Staff_No, p.Year_D, p.Month_D, p.Column_Index, COUNT(*) AS Column_Value
FROM Params p
JOIN Staff_Manager.dbo.Staff_Time_TBL t
ON p.Staff_No = t.Staff_No
WHERE t.Date_Data BETWEEN '2016/6/1' AND '2016/7/1'
AND t.Info_Data = 'Data_1'
GROUP
BY p.Staff_No, p.Year_D, p.Month_D, p.Column_Index, t.Info_Data
)
MERGE Staff_Manager.dbo.Staff_Count_TBL t
USING ParamsWithCount p
ON t.Staff_No = p.Staff_No
AND t.Year_D = p.Year_D
AND t.Month_D = p.Month_D
AND t.Column_Index = p.Column_Index
WHEN MATCHED THEN
UPDATE
SET Column_Value = p.Column_Value
WHEN NOT MATCHED THEN
INSERT ( Staff_No, Year_D, Month_D, Column_Index, Column_Value )
VALUES ( p.Staff_No, p.Year_D, p.Month_D, p.Column_Index, p.Column_Value );
我也不禁想知道Date_Data BETWEEN '2016/6/1' AND '2016/7/1'
的硬编码逻辑是否与参数值Year_D = 2016 AND Month_D = 6
有关。
这可以用一个表值参数代替上面的params
CTE。类似的东西:
CREATE TYPE Staff_Count_Type AS TABLE
(
Staff_No INT,
Year_D INT,
Month_D INT,
Column_Index INT
);
CREATE PROCEDURE UpateOrCreateStaffCount
@params Staff_Count_Type READONLY
AS
WITH ParamsWithCount AS
(
SELECT p.Staff_No, p.Year_D, p.Month_D, p.Column_Index, COUNT(*) AS Column_Value
FROM @params p
JOIN Staff_Manager.dbo.Staff_Time_TBL ...snipped...