Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
SQL Server查询优化:自内部联接过多_Sql_Sql Server_Sql Server 2012_Query Optimization - Fatal编程技术网

SQL Server查询优化:自内部联接过多

SQL Server查询优化:自内部联接过多,sql,sql-server,sql-server-2012,query-optimization,Sql,Sql Server,Sql Server 2012,Query Optimization,我目前正在尝试改进SQLServer上的SQL查询 我的工作台如下所示: 猫科历史 我的目标是检索他们类别的历史。 到目前为止,我正在这样做: SELECT A.DATE ,COUNT(DISTINCT A.ID) AS NB_CLIENTS ,A.CATEGORY AS STARTING_CAT ,B.CATOGORY AS ENDING_CAT FROM CAT_HISTORY A INNE

我目前正在尝试改进SQLServer上的SQL查询

我的工作台如下所示:

猫科历史

我的目标是检索他们类别的历史。 到目前为止,我正在这样做:

 SELECT   A.DATE
         ,COUNT(DISTINCT A.ID) AS NB_CLIENTS
         ,A.CATEGORY           AS STARTING_CAT
         ,B.CATOGORY           AS ENDING_CAT

FROM CAT_HISTORY A
INNER JOIN CAT_HISTORY B 
ON (
     A.ID= B.ID
 AND
 ( 
    ( 
          A.DATE = 20121201
      AND B.DATE = 20131201 
    )
  OR  
    (
          A.DATE  = 20131201
      AND B.DATE  = 20141201
    )

  WHERE A.DATE>= 20121201 AND B.DATE<= 20141201
  GROUP BY A.DATE, A.CATEGORY,B.CATEGORY
  ORDER BY A.DATE, A.CATEGORY,B.CATEGORY
但问题是我有更多的日期,我为每个日期添加一个OR,大约15个不同的日期,我有大量的用户。这意味着查询有时需要15分钟才能得到结果

我相信我的内心世界是残酷的,也许有一种更优雅、更有效的方式来达到预期的结果

我的最终目标是获得一个Sankey,以查看随着时间的推移从一个类别到另一个类别的演变,我需要在到日期之间从一个类别移动到另一个类别的用户数量

使用Gordon Linoff的答案,它工作得很好,但正在计算重复项

SELECT DISTINCT DATE, CATEGORY,NEXT_CATEGORY, COUNT(*) AS NB_CLIENTS
FROM (  
        SELECT DISTINCT CH.*, LEAD(CATEGORY) OVER (PARTITION BY CH.ID ORDER BY DATE) AS NEXT_CATEGORY
        FROM CAT_HISTORY CH 
        ) CH
        WHERE  NEXT_CATEGORY IS NOT NULL
        GROUP BY DATE, CATEGORY,NEXT_CATEGORY
例如: 期望

使用您的解决方案:

DATE_KEY     STARTING_CAT ENDING_CAT   NB_CLIENTS 
-----------  -----------  -----------  -----------
20121201     1            1            1
20121201     1            2            1
20121201     1            4            1
20121201     2            3            1
20131201     2            3            1
20131201     4            2            1
20131201     2            3            1
20141201     2            2            1
上次编辑:

我设法找到了一个解决办法:

 SELECT DISTINCT DATE, CATEGORY,NEXT_CATEGORY, COUNT(*) AS NB_CLIENTS
    FROM (  
            SELECT DISTINCT CH.*, LEAD(CATEGORY) OVER (PARTITION BY CH.ID ORDER BY DATE) AS NEXT_CATEGORY
            FROM (SELECT DISTINCT * FROM CAT_HISTORY) CH 
            ) CH
            WHERE  NEXT_CATEGORY IS NOT NULL
            GROUP BY DATE, CATEGORY,NEXT_CATEGORY

如果您希望看到成对的更改,那么使用提前期而不是固定日期。在SQL Server 2012+中,您可以执行以下操作:

select date, category, next_category, count(*)
from (select ch.*,
             lead(category) over (partition by id order by date) as next_category
      from cat_history ch
     ) ch
group by date, category, next_category;

在早期版本的SQL Server中,您可以对相关子查询或应用使用类似的逻辑。

如果希望看到成对的更改,请使用提前期而不是固定日期。在SQL Server 2012+中,您可以执行以下操作:

select date, category, next_category, count(*)
from (select ch.*,
             lead(category) over (partition by id order by date) as next_category
      from cat_history ch
     ) ch
group by date, category, next_category;

在早期版本的SQL Server中,您可以对相关子查询使用类似的逻辑或应用。

请检查此项,我将日期字段替换为日期字段


请检查此项,我将日期字段替换为日期字段


非常感谢您的回答,它工作的很好,但我现在有问题的事实,工作表有重复。我已经用细节编辑了我的帖子。@AxelR。你应该问另一个问题,而不是改变一个已经有答案的问题。我的错,我不想垃圾邮件问题:/非常感谢你的回答,它很好,但我现在有问题的事实,工作表有重复。我已经用细节编辑了我的帖子。@AxelR。你应该问另一个问题,而不是改变一个已经有答案的问题。糟糕,我不想滥发问题:/谢谢你的回答。我在使用它时遇到了问题,因为datefield在我这边是一个整数,而查询在执行它时会返回算术溢出。究竟为什么要将日期存储为整数,这是一种非常糟糕的做法。我们接收来自不同时区的日期,并且我们希望避免日期转换,我们决定将它们的原始值作为整数插入。谢谢您的回答。我在使用它时遇到了问题,因为datefield在我这边是一个整数,而查询在执行它时会返回算术溢出。究竟为什么要将日期存储为整数,这是一种非常糟糕的做法。我们接收来自不同时区的日期,并且我们希望避免日期转换,我们决定将其原始值作为整数插入。我更新了我的答案,您有问题,因为我没有添加具有结构的样本数据。关于您的输出结果,有一件事我不明白,NB_客户端如何根据您的输入数据拥有5、1、1、13个数据,请解释一下。所以请给出更好的答案。谢谢你,我设法让它工作了。我用相应的数据更新了我的答案。我更新了我的答案,你们有问题,因为我并没有用结构添加样本数据。关于您的输出结果,有一件事我不明白,NB_客户端如何根据您的输入数据拥有5、1、1、13个数据,请解释一下。所以请给出更好的答案。谢谢你,我设法让它工作了。我已经用相应的数据更新了我的答案。
 SELECT DISTINCT DATE, CATEGORY,NEXT_CATEGORY, COUNT(*) AS NB_CLIENTS
    FROM (  
            SELECT DISTINCT CH.*, LEAD(CATEGORY) OVER (PARTITION BY CH.ID ORDER BY DATE) AS NEXT_CATEGORY
            FROM (SELECT DISTINCT * FROM CAT_HISTORY) CH 
            ) CH
            WHERE  NEXT_CATEGORY IS NOT NULL
            GROUP BY DATE, CATEGORY,NEXT_CATEGORY
select date, category, next_category, count(*)
from (select ch.*,
             lead(category) over (partition by id order by date) as next_category
      from cat_history ch
     ) ch
group by date, category, next_category;
declare @t table(datefield date , id varchar(10) , category int )

insert into @t values
(cast( '20121201' as date) , 'A', 1),
(cast( '20121201' as date) , 'B', 1),
(cast( '20121201' as date) , 'C', 2),
(cast( '20131201' as date) , 'A', 2),
(cast( '20131201' as date) , 'B', 4),
(cast( '20131201' as date) , 'C', 3),
(cast( '20141201' as date) , 'A', 3),
(cast( '20141201' as date) , 'B', 2),
(cast( '20141201' as date) , 'C', 1)

SELECT   A.datefield
         ,COUNT(DISTINCT A.ID) AS NB_CLIENTS
         ,A.CATEGORY           AS STARTING_CAT
         ,isnull(B.CATEGORY ,0)       AS ENDING_CAT
FROM @T A
left JOIN @T B 
ON 
    ( 
        A.ID= B.ID   AND 
        ( b.datefield =  dateadd( yy, 1 , a.datefield ) ) 
    )
 -- WHERE A.datefield>= '20121201' AND ( B.datefield<= '20141201' or B.datefield is null)
  GROUP BY A.datefield, A.CATEGORY,B.CATEGORY
  ORDER BY A.datefield, A.CATEGORY,B.CATEGORY