SQL Server:子查询到Join语句

时间:2014-11-14 16:20:03

标签: sql sql-server

我试图在我的数据库中查询过去3天内每个用户所做的记录(电话)数量(例如)。

我试图实现以下查询输出:

username     10-11-2014  11-11-2014   12-11-2014
user1         24          25           20
user2         23          20           30

我可以使用以下查询来执行此操作,但对我来说,这似乎是一个非常漫长的方式,我认为我能够使用连接来做到这一点,但我不知道。

SELECT username, 
    (SELECT count(tblCall.call_id) 
     FROM tblCall 
     WHERE tblCall.started_at BETWEEN '2014-11-10 00:00:00' AND 
           '2014-11-10 23:00:00' AND 
           tblCall.from_user_id = tblUser.user_id) AS '10-11-2014',
           (SELECT count(tblCall.call_id) 
            FROM tblCall
            WHERE tblCall.started_at BETWEEN '2014-11-11 00:00:00' AND 
                 '2014-11-11 23:00:00' AND 
                  tblCall.from_user_id = tblUser.user_id) AS '11-11-2014',
           (SELECT count(tblCall.call_id) 
            FROM tblCall 
            WHERE tblCall.started_at BETWEEN '2014-11-12 00:00:00' AND 
                  '2014-11-12 23:00:00' AND
                  tblCall.from_user_id = tblUser.user_id) AS '12-11-2014'
FROM tblUser
WHERE tblUser.can_manage_accounts = '1' AND 
      tblUser.telephone_ext != '' AND 
      tblUser.blocked = '0'
GROUP BY tblUser.user_id, tblUser.username

我希望能够指定查询呼叫的日期范围,并让它们每天都返回到新列中。这可能吗?

谢谢!

2 个答案:

答案 0 :(得分:2)

试试这个......

SELECT username 
    ,count(CASE WHEN tblCall.started_at BETWEEN '2014-11-10 00:00:00' AND '2014-11-10 23:00:00' THEN tblCall.call_id ELSE NULL END)  AS [10-11-2014]
    ,count(CASE WHEN tblCall.started_at BETWEEN '2014-11-11 00:00:00' AND '2014-11-11 23:00:00' THEN tblCall.call_id ELSE NULL END)  AS [11-11-2014]
    ,count(CASE WHEN tblCall.started_at BETWEEN '2014-11-12 00:00:00' AND '2014-11-12 23:00:00' THEN tblCall.call_id ELSE NULL END)  AS [12-11-2014]
FROM tblUser 
INNER JOIN tblCall ON tblCall.from_user_id = tblUser.[user_id]
WHERE tblUser.can_manage_accounts = '1' 
  AND tblUser.telephone_ext != '' 
  AND tblUser.blocked = '0'
GROUP BY tblUser.username

动态Sql

CREATE TABLE TEST_TABLE(UserName VARCHAR(100), started_at DATETIME)
GO
INSERT INTO TEST_TABLE VALUES 
('Mark' , '2014-11-13 23:59:59.997'),('Jane' , '2014-11-13 23:59:59.997'),('Sam' , '2014-11-13 23:59:59.997'),
('Mark' , '2014-11-13 23:59:59.997'),('Jane' , '2014-11-13 23:59:59.997'),('Sam' , '2014-11-13 23:59:59.997'),
('Holly' ,'2014-11-12 23:59:59.997'),('Sally' ,'2014-11-12 23:59:59.997'),('Mandy' ,'2014-11-12 23:59:59.997'),
('Holly' ,'2014-11-12 23:59:59.997'),('Sally' ,'2014-11-12 23:59:59.997'),('John' ,'2014-11-11 23:59:59.997'),
('James' ,'2014-11-11 23:59:59.997'),('John' ,'2014-11-11 23:59:59.997'),('James' ,'2014-11-11 23:59:59.997'),
('Josh' ,'2014-11-10 23:59:59.997'),('Jamie' ,'2014-11-10 23:59:59.997')
GO

查询

DECLARE @Range_Start DATE =  '2014-11-11'
DECLARE @Range_End   DATE =  '2014-11-13'

DECLARE @Date_Columns NVARCHAR(MAX); 
DECLARE @Sql          NVARCHAR(MAX); 


SELECT @Date_Columns = STUFF(( SELECT DISTINCT  ', ' + QUOTENAME(CONVERT(VARCHAR(10), started_at, 120)) 
                        FROM TEST_TABLE
                        WHERE CAST(started_at AS DATE) >= @Range_Start
                         AND  CAST(started_at AS DATE) <= @Range_End
                        FOR XML PATH(''),TYPE).value('.','NVARCHAR(MAX)'),1,2,'')                   

SET @Sql = N' SELECT * 
            FROM (
                  SELECT UserName, COUNT(*) AS Total,  CONVERT(VARCHAR(10), started_at, 120) AS started_at
                  FROM TEST_TABLE
                  WHERE CAST(started_at AS DATE) >= @Range_Start
                   AND  CAST(started_at AS DATE) <= @Range_End
                  GROUP BY UserName, CONVERT(VARCHAR(10), started_at, 120) 
                  ) t
                 PIVOT ( SUM(Total)
                         FOR started_at
                         IN (' + @Date_Columns + ')
                         )p '

Execute sp_executesql @Sql 
                     ,N'@Range_Start DATE, @Range_End   DATE'
                     ,@Range_Start   
                     ,@Range_End

结果

╔══════════╦════════════╦════════════╦════════════╗
║ UserName ║ 2014-11-11 ║ 2014-11-12 ║ 2014-11-13 ║
╠══════════╬════════════╬════════════╬════════════╣
║ Holly    ║ NULL       ║ 2          ║ NULL       ║
║ James    ║ 2          ║ NULL       ║ NULL       ║
║ Jane     ║ NULL       ║ NULL       ║ 2          ║
║ John     ║ 2          ║ NULL       ║ NULL       ║
║ Mandy    ║ NULL       ║ 1          ║ NULL       ║
║ Mark     ║ NULL       ║ NULL       ║ 2          ║
║ Sally    ║ NULL       ║ 2          ║ NULL       ║
║ Sam      ║ NULL       ║ NULL       ║ 2          ║
╚══════════╩════════════╩════════════╩════════════╝

答案 1 :(得分:0)

您需要使用Dynamic Sql

DECLARE @cols       VARCHAR(max)='',
        @sql        NVARCHAR(max),
        @start_date DATETIME='2009-08-25 00:00:00',--start date
        @end_date   DATETIME='2009-09-02 00:00:00'--end date

SELECT @cols += ',[' + CONVERT(VARCHAR(30), started_at, 102)+ ']'
FROM   (SELECT DISTINCT CONVERT(DATE, started_at) started_at
        FROM   #tblCall
        WHERE  started_at BETWEEN @start_date AND @end_date) A

SELECT @cols = RIGHT(@cols, Len(@cols) - 1)

SET @sql='SELECT *
FROM   (SELECT Count(call_id)            cnt,
               CONVERT(DATE, started_at) started_at,
               userid
        FROM   #tblCall where started_at between '''+ CONVERT(VARCHAR(30), @start_date, 102)+ ''' and '''
         + CONVERT(VARCHAR(30), @end_date, 102)
         + ''' GROUP  BY userid,
                  CONVERT(DATE, started_at)) A
       PIVOT (Max(cnt)
             FOR started_at IN (' + @cols + ')) piv'

EXEC Sp_executesql @sql