2016-07-14 213 views
0

我有两个表,Table_1Table_2结合两个SQL查询?

我正在使用此SQL语句来计算Table_1Info_Data列中特定数据段的发生次数。在目前的硬编码的形式返回的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 

一个值,那么我有一个检查,看看是否在Table_2存在一排,如果没有,插入一行,并更新数据的另一个SQL语句。如果是这样,只需更新数据即可。

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,我要替换该行SET Column_Value = 9硬编码9Column_Value列在这条线VALUES (3201, 2016, 6, 1, 9)重视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 

回答

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没有价值观建设,了解更多详情阅读http://www.w3schools.com/sql/sql_insert_into_select.asp。另请参阅How do I UPDATE from a SELECT in SQL Server?

P.S.单个查询不需要使用BEGIN/END,它们可以跳过。

+0

哦,我明白你的意思。谢谢你,这很好。 – KyloRen

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


这可以被制作成带有一个表值参数一个PROC代替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... 
+0

感谢您花时间回答。是硬编码的月份和年份与日期直接相关。当把它放到C#中时,我根本没有任何硬编码数据。我不确定我遵循“表值参数”的含义。再次感谢。投票的帮助和很好的答案。顺便说一句,伟大的作品。 – KyloRen

+0

用带表值参数的proc概述进行更新。 – onedaywhen