Tsql SQL:Spread Count()按多列中的条件排列

Tsql SQL:Spread Count()按多列中的条件排列,tsql,count,query-optimization,Tsql,Count,Query Optimization,我有一个名为[Tote]的表,其中列出了进入或进入站点的手提袋,如下所示: Id Barcode Checksum PackageType Sts Destination LastStationExit LastUpdated ----------- ------------------ ----------- ----------- ----------- ----------- --------------- ----------

我有一个名为[Tote]的表,其中列出了进入或进入站点的手提袋,如下所示:

Id          Barcode            Checksum    PackageType Sts         Destination LastStationExit LastUpdated
----------- ------------------ ----------- ----------- ----------- ----------- --------------- -----------------------
-2147483645 777000000000000001 586965230   0           1           NULL        MS32            2016-04-19 14:15:32.577
-2147483644 777000000000000002 821846254   0           1           MS01        NULL            2016-04-19 15:08:16.140
-2147483643 777000000000000003 1174167790  0           1           NULL        MS02            2016-04-19 15:08:20.340
-2147483642 777000000000000004 1543266542  0           1           NULL        MS31            2016-04-19 15:08:24.510
-2147483641 777000000000000005 3424831     0           1           NULL        MS01            2016-04-19 15:08:31.060
-2147483640 777000000000000006 573850175   0           1           MS01        NULL            2016-04-19 15:08:34.200
我有另一个表,其中包含所有名为[MezzanineStation]的现有站点:

Name
----
MS01
MS02
MS11
MS12
MS21
MS22
MS31
MS32
我试图计算,对于每个站点,有多少个手提袋将到达目的地=站点名称,以及有多少个手提袋将进入站点LastStationExit=站点名称

我编写了以下正确运行的请求:

-- Création d'une variable tampon pour isoler les bacs concernés par le calcul
DECLARE @FilteredToteExtract TABLE
(
   Destination Varchar(4),
   LastStationExit Varchar(4)
)
INSERT INTO @FilteredToteExtract([Destination],[LastStationExit])
SELECT [Destination],[LastStationExit]
FROM [Tote] T
WHERE [PackageType]=0
    AND LastUpdated>=DATEADD(HOUR,-12,GETDATE())
    AND EXISTS (SELECT * FROM [MezzanineStation] MS WHERE MS.[Name]=T.[Destination] OR MS.[Name]=T.[LastStationExit])

-- Calcul de l'occupation (prévue et courante) des gares de la mezzanine
SELECT DISTINCT MS.Name,T_Destination.[Count] AS NbTotesOngoing,T_LastStationExit.[Count] AS NbTotesInside
FROM [MezzanineStation] MS
LEFT JOIN
( SELECT
    Destination,
    COUNT(*) AS [Count]
  FROM @FilteredToteExtract
  GROUP BY Destination
) T_Destination
ON MS.Name = T_Destination.Destination
LEFT JOIN
( SELECT
    LastStationExit,
    COUNT(*) AS [Count]
  FROM @FilteredToteExtract
  GROUP BY LastStationExit
) T_LastStationExit
ON MS.Name = T_LastStationExit.LastStationExit
它给了我这样的结果:

Name NbTotesOngoing NbTotesInside
---- -------------- -------------
MS01 2              1
MS02 NULL           1
MS11 NULL           NULL
MS12 NULL           NULL
MS21 NULL           NULL
MS22 NULL           NULL
MS31 NULL           1
MS32 NULL           NULL
以下是我在[Tote]表上创建的索引:

CREATE INDEX IX_Tote_PackageType ON [Tote]([PackageType])
CREATE INDEX IX_Tote_LastStationExit ON [Tote]([LastStationExit])
CREATE INDEX IX_Tote_LastUpdated ON [Tote]([LastUpdated])

您认为此请求可以更优化吗?

如果您尚未使用GROUP by替换DISTINCT,您可以尝试。有时,这会产生积极的影响,因为将使用不同的执行计划,这可能会影响性能


如果您需要提高性能,并且根据您的需求,您可能希望使用内存优化的表变量而不是普通的表变量:

除非夹层设置中有重复项,否则您不需要使用distinct 如果要具体化,则使用带有索引的临时文件,而不是表 但我不认为你需要具体化 关于LastUpdated的索引可能会有所帮助

SELECT MSM.[Name], TD.Count as TDcount, TL.Count as TLcount
  FROM [MezzanineStation] MSM
  LEFT JOIN ( SELECT MS.[Name], count(T.[Destination]) as [Count]
                FROM [Tote] T
                JOIN [MezzanineStation] MS
                      ON MS.[Name] = T.[Destination] 
               WHERE T.[PackageType] = 0
                 AND T.LastUpdated >= DATEADD(HOUR,-12,GETDATE())
               GROUP BY MS.[Name]
            ) as TD
              ON TD.[Name] = MSM.[Name]
  LEFT join ( SELECT MS.[Name], count(T.[LastStationExit]) as count
                FROM [Tote] T
                JOIN [MezzanineStation] MS
                       ON MS.[Name] = T.[LastStationExit])
               WHERE T.[PackageType] = 0
                 AND T.LastUpdated >= DATEADD(HOUR,-12,GETDATE()) 
               GROUP BY MS.[Name] 
             ) as TL
               ON TL.[Name] = MSM.[Name]
如果其中一列始终为null,那么它很简单

SELECT MS.[Name]
     , count(T.[Destination]) as [DestinationCount]
     , count(T.[LastStationExit]) as [LastStationExitCount]
  FROM [MezzanineStation] MS
  LEFT JOIN [Tote] T
         ON MS.[Name] = isnull(T.[Destination], T.[LastStationExit])  
 WHERE T.[PackageType] = 0
   AND T.LastUpdated >= DATEADD(HOUR,-12,GETDATE())
 GROUP BY MS.[Name]

所以,最新的版本很好,完全符合接吻要求^ ^ ^多亏了狗仔队

CREATE FUNCTION dbo.GetMezzanineStationOccupancyForTotes()
RETURNS @StationOccupancy TABLE
(
   [Level]           Int            NOT NULL,   -- Niveau de la gare
   [Priority]        Int            NOT NULL,   -- Ordre de priorité spécifié dans la supervision (0 = Priorité la + élevée)
   [Name] T_MEZZANINE_STATION_NAME  NOT NULL,   -- Nom de la gare
   [Open]            Bit NOT NULL,  -- Ouverture/Fermeture de la gare (TRUE = Gare ouverte)
   [NbTotesOngoing]  Int,           -- Nombre de bacs à destination de la gare
   [NbTotesInside]   Int,           -- Nombre de bacs présents dans la gare
   [StationOccupancy] AS [NbTotesOngoing]+[NbTotesInside]   -- Occupation de la gare
)
AS
   BEGIN
   /* Constantes */
   --<CST=ENU_TOTES_PACKAGE_TYPE>
   -- Equivalent de l'énumération ENU_TOTES_PACKAGE_TYPE
   DECLARE @TOTES_PACKAGE_TYPE_TOTE       Int = 0, -- Bac
           @TOTES_PACKAGE_TYPE_RETURN_BOX Int = 1, -- Carton retour
           @MX_TOTES_PACKAGE_TYPE         Int = 2
   --</CST=ENU_TOTES_PACKAGE_TYPE>

   /* Variables locales */
   DECLARE @OldestIdleTime DateTime -- Date de dernière mise à jour la plus ancienne à prendre en compte

   SELECT @OldestIdleTime=DATEADD(HOUR,-[NbHoursForgetTote],GETDATE())
   FROM [Parameter] (NOLOCK)

   -- Création d'une variable tampon pour isoler les bacs concernés par le calcul
   DECLARE @FilteredToteExtract TABLE
   (
      Destination Varchar(4),
      LastStationExit Varchar(4)
   )
   INSERT INTO @FilteredToteExtract([Destination],[LastStationExit])
   SELECT [Destination],[LastStationExit]
   FROM [Tote] T (NOLOCK)
   WHERE [PackageType]=@TOTES_PACKAGE_TYPE_TOTE
       AND LastUpdated>=@OldestIdleTime
       AND EXISTS (SELECT * FROM [MezzanineStation] MS WHERE MS.[Name]=T.[Destination] OR MS.[Name]=T.[LastStationExit])

   /* Fonction */
   -- Calcul de l'occupation (prévue et courante) des gares de la mezzanine
   INSERT INTO @StationOccupancy
   SELECT
      MS.[Level],
      MS.[Priority],
      MS.[Name],
      MS.[Open],
      ISNULL(COUNT(T.[Destination]),0),
      ISNULL(COUNT(T.[LastStationExit]),0)
   FROM [MezzanineStation] MS (NOLOCK)
   LEFT JOIN @FilteredToteExtract T
      ON MS.[Name] = ISNULL(T.[Destination],T.[LastStationExit])  
   GROUP BY MS.[Name],MS.[Level],MS.[Priority],MS.[Open]

   /* Résultats */
   RETURN
   END

我删除了明显的原因,因为[MezzanineStation]中确实没有重复项。实际上,每个记录的其中一列应该始终为空,因为一个手提包不能同时在一个站点和一个站点中。。。起初,我设计它是为了处理奇怪的情况,其中没有一个是空的,但你是对的,我会像你说的那样简化它^ ^对于另一位客户,我曾尝试通过触发器更新此类列,但它的性能非常差,所以现在我只是用其他数据更新它……为什么我被否决了?我认为给出正确而简洁的答案会很好。