简体   繁体   中英

Combine two SQL queries?

I have two tables, Table_1 and Table_2 .

I am using this SQL statement to count how many times a particular piece of data occurs in column Info_Data in Table_1 . In its current hard coded form it returns a value of 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

I then have another SQL statement that checks to see if a row exists in Table_2 , if it does not, insert a row and update the data. If it does ,just update the data.

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

Both these statements are working how they are supposed to.

But I can't find a way to combine the two statements, I tried JOIN , MERGE with no luck. Being that the value that the first statement returns is 9 , I want to replace the hard coded 9 on this line SET Column_Value = 9 and the Column_Value columns value 9 on this line VALUES (3201, 2016, 6, 1, 9) with result of the first statement

This obviously is incorrect, but to illustrate what I am sort of trying to do.

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

Your first query returns more than one column and you can't use it to update or insert a single column. Instead, make it to return only count() and try

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

and

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

As you can see, in INSERT there is no VALUES construction, read http://www.w3schools.com/sql/sql_insert_into_select.asp for more details. Also see how to How do I UPDATE from a SELECT in SQL Server? .

PS Using of BEGIN/END is not required for single queries and they could be skipped.

The redundancy in the two statements in the accepted answer bothers me ie a change to one business rules would need to be changed in at least two places.

So here's my attempt at writing the equivalent MERGE statement (trust you can see the potential for a table-valued parameter here):

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 );

I also can't help wondering whether the hard-coded logic of Date_Data BETWEEN '2016/6/1' AND '2016/7/1' in fact relates to the parameter values Year_D = 2016 AND Month_D = 6 .


This could be made into a proc with a table-valued parameter in place of the params CTE above eg something like:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM