【问题标题】:How does the following code read and look in T-SQL?以下代码如何在 T-SQL 中读取和查看?
【发布时间】:2014-04-01 22:01:27
【问题描述】:
 The code originates from the following post: 

What SQL can I use to retrieve counts from my payments data?

我正在处理大量数据,并且此代码(在 MS-ACCESS JET SQL 中)目前需要大约 10-15 分钟来查询(当它不崩溃时)。我想提高查询运行的速度,这就是为什么我希望使用直通查询方法。目前,我使用的后端数据库是 SQL Server (2012),我使用 ODBC 连接进行链接。

我的印象是,用后端数据库的语言编写 SQL 可以更有效地执行直通查询。我相信 T-SQL 将成为语言。我做了研究,确实没有“JET-SQL 到 T-SQL 转换器”。因此,请问是否有人对以下代码在 T-SQL 中的读取和外观有任何建议。

    TRANSFORM Nz(First(CountOfStudents),0) AS n
SELECT 
    YearNumber,
    MonthNumber,
    School
FROM
    (
        SELECT
            YearNumber,
            MonthNumber,
            School,
            [School Service Type],
            COUNT(*) AS CountOfStudents
        FROM
            (
                SELECT DISTINCT
                    mtr.YearNumber,
                    mtr.MonthNumber,
                    pym.[Student ID],
                    pym.School,
                    pym.[School Service Type]
                FROM
                    MonthsToReport AS mtr
                    INNER JOIN
                    PaymentsYearMonth AS pym
                        ON mtr.YYYYMM>=pym.StartYYYYMM 
                            AND mtr.YYYYMM<=pym.EndYYYYMM
            ) AS distinctQuery
        GROUP BY 
            YearNumber,
            MonthNumber,
            School,
            [School Service Type]
    ) AS countQuery
GROUP BY
    YearNumber,
    MonthNumber,
    School
PIVOT [School Service Type]

一如既往,感谢您抽出宝贵时间。

【问题讨论】:

  • 您的具体问题是“我怎样才能使这个查询执行得更快”?如果您使用的是 SQL Server Management Studio,那么当您执行查询时,您可以检查查询执行计划,这将帮助您调试查询的性能。您可以识别执行计划中涉及繁重的 CPU 工作(例如表扫描)或传递的记录过多的部分。从那里您可以针对存在实际性能问题的性能改进。
  • @David:目前,当我使用 SQL Server Management Studio 时,在尝试运行上面提供的查询时出现错误。我认为是这种情况的原因是查询当前是用 MS-Access 的本机 SQL (JET SQL) 编写的,后端 SQL Server 无法读取(没有 MS Access 翻译它)。
  • 将 nz 更改为 coalesce 并重试。 nz 是 VBA 进入您的查询。 coalesce 是 T-SQL 等价物。
  • @Brad:你的合并建议不走运。
  • 第一步找到在你的列名中加空格的人。第二步打那个人的脸。

标签: sql database tsql ms-access jet


【解决方案1】:

将 Access SQL 交叉表查询转换为 T-SQL 只是该过程的一部分。为了将所有处理推送到 SQL Server 上,我们还需要确保所有依赖项也在 SQL Server 上。 (例如,在 SQL Server 上运行的 T-SQL 查询将无法从 Access 中保存的查询中提取数据。)

按照previous question 中的步骤,我们在 SQL Server 上有名为 [Payments] 的表:

Payment Row  Student ID  School  School Service Type  PaymentStartDate  PaymentEndDate
-----------  ----------  ------  -------------------  ----------------  --------------
          1  001         ABC     ED                   2010-01-02        2012-02-04    
          2  001         ABC     ED                   2010-01-02        2010-01-05    
          3  001         ABC     ED                   2010-04-02        2010-05-05    
          4  001         DEF     EZ                   2010-01-02        2012-02-04    
          5  001                 RR                   2012-02-02        2012-02-03    
          6  002         ABC     ED                   2010-02-02        2011-02-03    
          7  002         ABC     EZ                   2010-02-02        2010-06-03    
          8  002         GHI     ED                   2011-02-04        2012-02-04    
          9  003         ABC     ED                   2011-02-02        2012-02-03    
         10  003         DEF     ED                   2010-01-02        2010-08-03    
         11  003                 RR                   2011-02-02        2011-02-03    
         12  004                 RR                   2011-02-02        2011-02-03    
         13  005         GHI     ED                   2010-08-02        2011-02-04    
         14  006         GHI     ED                   2010-08-02        2010-08-02    

我们在 SQL Server 中创建 [PaymentsYearMonth] 视图

CREATE VIEW PaymentsYearMonth AS
SELECT 
    [Student ID], 
    School, 
    [School Service Type], 
    (Year(PaymentStartDate) * 100) + Month(PaymentStartDate) AS StartYYYYMM, 
    (Year(PaymentEndDate) * 100) + Month(PaymentEndDate) AS EndYYYYMM
FROM Payments

SQL Server 还需要有我们的 [MonthNumbers] 表的副本

MonthNumber
-----------
          1
          2
          3
          4
          5
          6
          7
          8
          9
         10
         11
         12

还有我们的 [YearNumbers] 表

YearNumber
----------
      2009
      2010
      2011
      2012
      2013

所以现在我们可以创建 [MonthsToReport] 视图。 T-SQL没有DMin()和DMax()函数,所以我们需要稍微改变一下查询

CREATE VIEW MonthsToReport AS
SELECT
    yn.YearNumber,
    mn.MonthNumber,
    (yn.YearNumber * 100) + mn.MonthNumber AS YYYYMM
FROM
    YearNumbers AS yn,
    MonthNumbers AS mn
WHERE ((yn.YearNumber * 100) + mn.MonthNumber)>=(SELECT MIN(StartYYYYMM) FROM PaymentsYearMonth)
    AND ((yn.YearNumber * 100) + mn.MonthNumber)<=(SELECT MAX(EndYYYYMM) FROM PaymentsYearMonth)

计算不同行的 SQL 查询完全相同,所以让我们为此创建一个视图,以便在下一步执行 PIVOT 时更容易看到发生了什么

CREATE VIEW DistinctCountsByMonth AS
SELECT
    YearNumber,
    MonthNumber,
    School,
    [School Service Type],
    COUNT(*) AS CountOfStudents
FROM
    (
        SELECT DISTINCT
            mtr.YearNumber,
            mtr.MonthNumber,
            pym.[Student ID],
            pym.School,
            pym.[School Service Type]
        FROM
            MonthsToReport AS mtr
            INNER JOIN
            PaymentsYearMonth AS pym
                ON mtr.YYYYMM>=pym.StartYYYYMM 
                    AND mtr.YYYYMM<=pym.EndYYYYMM
    ) AS distinctQuery
GROUP BY 
    YearNumber,
    MonthNumber,
    School,
    [School Service Type]

现在,如果我们在 Access 中进行交叉表查询,那就是

TRANSFORM First(CountOfStudents) AS n
SELECT YearNumber, MonthNumber, School
FROM DistinctCountsByMonth
GROUP BY YearNumber, MonthNumber, School
PIVOT [School Service Type]

但是 T-SQL 中的 PIVOT 子句要求我们给它实际的列名列表(与 Access 不同,它可以自动生成列名)。因此,我们将在 SQL Server 上创建一个存储过程,用于构建列名列表、构造 SQL 语句并执行它:

CREATE PROCEDURE DistinctPaymentsCrosstab
AS
BEGIN
    SET NOCOUNT ON;
    DECLARE 
            @ColumnList AS NVARCHAR(MAX),
            @SQL AS NVARCHAR(MAX)

    -- build the list of column names based on the current contents of the table
    --     e.g., '[ED],[EZ],[RR]'
    --     required by PIVOT ... IN below
    --     ref: https://stackoverflow.com/a/14797796/2144390     
    SET @ColumnList = 
            STUFF(
                (
                    SELECT DISTINCT ',' + QUOTENAME([School Service Type])
                    FROM [DistinctCountsByMonth] 
                    FOR XML PATH(''), TYPE
                ).value('.', 'NVARCHAR(MAX)'), 
                1, 
                1, 
                '')
    SET @SQL = '
            WITH rollup
            AS
            (
                SELECT 
                    [School Service Type], 
                    YearNumber, 
                    MonthNumber, 
                    School, 
                    SUM(CountOfStudents) AS n 
                FROM [DistinctCountsByMonth]
                GROUP BY 
                    [School Service Type],
                    YearNumber, 
                    MonthNumber, 
                    School
            )
            SELECT * FROM rollup
            PIVOT (SUM([n]) FOR [School Service Type] IN (' + @ColumnList + ')) AS Results'
    EXECUTE(@SQL)
END

现在我们可以使用传递查询从 Access 调用该存储过程

返回

【讨论】:

    【解决方案2】:

    See Here 在 SSMS 中创建索引以优化您查询最多的数据。 (这会提高速度)

    See Here 关于直通查询。

    这两个链接都非常详细,应该可以帮助您到达您需要去的地方,并让您在此过程中学到一些东西。

    【讨论】:

      【解决方案3】:

      这是另一个 (1:1) 示例。 Jet-SQL 代码:

      TRANSFORM Count([qTeile-LF-Beziehungen_zuTeileImportListe _PLUS].Warnstufe) AS AnzahlvonWarnstufe
      SELECT [qTeile-LF-Beziehungen_zuTeileImportListe _PLUS].Lieferant
      FROM [qTeile-LF-Beziehungen_zuTeileImportListe _PLUS]
      GROUP BY [qTeile-LF-Beziehungen_zuTeileImportListe _PLUS].Lieferant
      PIVOT [qTeile-LF-Beziehungen_zuTeileImportListe _PLUS].Warnstufe;
      

      在 SQL-Server 上,代码是:

      SELECT  [Lieferant]
             ,ISNULL([ok], 0)   AS [ok]
             ,ISNULL([W180], 0) AS [W180]
             ,ISNULL([W360], 0) AS [W360]
             ,ISNULL([W720], 0) AS [W720]
      FROM  
      (
          SELECT  [Lieferant]
                 ,[Warnstufe] AS [AnzahlvonWarnstufe]
          FROM [dbo].[VIEW_qTeile-LF-Beziehungen_zuTeileImportListe_PLUS_Warnstufe]    
      ) src 
      pivot
      (
          COUNT([AnzahlvonWarnstufe])
          FOR [AnzahlvonWarnstufe] IN ([ok], [W180], [W360], [W720])
      
      ) piv;
      

      玩得开心。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-11-08
        • 1970-01-01
        • 2018-08-30
        • 1970-01-01
        • 1970-01-01
        • 2018-02-21
        • 2015-04-05
        • 2021-06-04
        相关资源
        最近更新 更多