结合两个SQL查询?

时间:2016-07-14 05:02:19

标签: sql sql-server

我有两个表,Table_1Table_2

我正在使用此SQL语句来计算Info_DataTable_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

这些陈述都是按照它们应有的方式运作的。

但我找不到合并这两种陈述的方法,我试过JOINMERGE没有运气。 由于第一个语句返回的值为9,我想替换此行9上的硬编码SET Column_Value = 9Column_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

2 个答案:

答案 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...