【问题标题】:SQL Help - Sales by State (SAP Business One)SQL 帮助 - 按州销售 (SAP Business One)
【发布时间】:2014-04-22 13:39:54
【问题描述】:

想知道是否有人可以帮助我处理我试图用来从我的数据库中提取销售信息的查询。我正在尝试建立一个报告来按州显示所有销售额。我遇到过这段代码,虽然它接近我所需要的,但它并没有完全发挥作用。

除了每个州的销售额外,我还需要包括销售库存的仓库 (T1.[WhsCode])。我还需要对每一列求和(我知道您可以按 Ctrl 并单击以在每列底部获取总计,但希望它们自动出现在最终报告中)。有人可以帮忙吗?

这是目前的查询:

SELECT  T0.State1 AS 'Bill-to State',
        (
          SELECT    SUM(T1.DocTotal)
          FROM      OINV T1 WITH ( NOLOCK )
          INNER JOIN OCRD T2 ON T2.CardCode = T1.CardCode
          WHERE     MONTH(T1.DOCDATE) = 1 AND
                    T2.State1 = T0.State1 AND
                    YEAR(T1.DOCDATE) = YEAR(GETDATE())
        ) AS 'JAN Amt',
        (
          SELECT    SUM(T1.DocTotal)
          FROM      OINV T1 WITH ( NOLOCK )
          INNER JOIN OCRD T2 ON T2.CardCode = T1.CardCode
          WHERE     MONTH(T1.DOCDATE) = 2 AND
                    T2.State1 = T0.State1 AND
                    YEAR(T1.DOCDATE) = YEAR(GETDATE())
        ) AS 'FEB Amt',
        (
          SELECT    SUM(T1.DocTotal)
          FROM      OINV T1 WITH ( NOLOCK )
          INNER JOIN OCRD T2 ON T2.CardCode = T1.CardCode
          WHERE     MONTH(T1.DOCDATE) = 3 AND
                    T2.State1 = T0.State1 AND
                    YEAR(T1.DOCDATE) = YEAR(GETDATE())
        ) AS 'MAR Amt',
        (
          SELECT    SUM(T1.DocTotal)
          FROM      OINV T1 WITH ( NOLOCK )
          INNER JOIN OCRD T2 ON T2.CardCode = T1.CardCode
          WHERE     MONTH(T1.DOCDATE) = 4 AND
                    T2.State1 = T0.State1 AND
                    YEAR(T1.DOCDATE) = YEAR(GETDATE())
        ) AS 'APR Amt',
        (
          SELECT    SUM(T1.DocTotal)
          FROM      OINV T1 WITH ( NOLOCK )
          INNER JOIN OCRD T2 ON T2.CardCode = T1.CardCode
          WHERE     MONTH(T1.DOCDATE) = 5 AND
                    T2.State1 = T0.State1 AND
                    YEAR(T1.DOCDATE) = YEAR(GETDATE())
        ) AS 'MAY Amt',
        (
          SELECT    SUM(T1.DocTotal)
          FROM      OINV T1 WITH ( NOLOCK )
          INNER JOIN OCRD T2 ON T2.CardCode = T1.CardCode
          WHERE     MONTH(T1.DOCDATE) = 6 AND
                    T2.State1 = T0.State1 AND
                    YEAR(T1.DOCDATE) = YEAR(GETDATE())
        ) AS 'JUN Amt',
        (
          SELECT    SUM(T1.DocTotal)
          FROM      OINV T1 WITH ( NOLOCK )
          INNER JOIN OCRD T2 ON T2.CardCode = T1.CardCode
          WHERE     MONTH(T1.DOCDATE) = 7 AND
                    T2.State1 = T0.State1 AND
                    YEAR(T1.DOCDATE) = YEAR(GETDATE())
        ) AS 'JUL Amt',
        (
          SELECT    SUM(T1.DocTotal)
          FROM      OINV T1 WITH ( NOLOCK )
          INNER JOIN OCRD T2 ON T2.CardCode = T1.CardCode
          WHERE     MONTH(T1.DOCDATE) = 8 AND
                    T2.State1 = T0.State1 AND
                    YEAR(T1.DOCDATE) = YEAR(GETDATE())
        ) AS 'AUG Amt',
        (
          SELECT    SUM(T1.DocTotal)
          FROM      OINV T1 WITH ( NOLOCK )
          INNER JOIN OCRD T2 ON T2.CardCode = T1.CardCode
          WHERE     MONTH(T1.DOCDATE) = 9 AND
                    T2.State1 = T0.State1 AND
                    YEAR(T1.DOCDATE) = YEAR(GETDATE())
        ) AS 'SEP Amt',
        (
          SELECT    SUM(T1.DocTotal)
          FROM      OINV T1 WITH ( NOLOCK )
          INNER JOIN OCRD T2 ON T2.CardCode = T1.CardCode
          WHERE     MONTH(T1.DOCDATE) = 10 AND
                    T2.State1 = T0.State1 AND
                    YEAR(T1.DOCDATE) = YEAR(GETDATE())
        ) AS 'OCT Amt',
        (
          SELECT    SUM(T1.DocTotal)
          FROM      OINV T1 WITH ( NOLOCK )
          INNER JOIN OCRD T2 ON T2.CardCode = T1.CardCode
          WHERE     MONTH(T1.DOCDATE) = 11 AND
                    T2.State1 = T0.State1 AND
                    YEAR(T1.DOCDATE) = YEAR(GETDATE())
        ) AS 'NOV Amt',
        (
          SELECT    SUM(T1.DocTotal)
          FROM      OINV T1 WITH ( NOLOCK )
          INNER JOIN OCRD T2 ON T2.CardCode = T1.CardCode
          WHERE     MONTH(T1.DOCDATE) = 12 AND
                    T2.State1 = T0.State1 AND
                    YEAR(T1.DOCDATE) = YEAR(GETDATE())
        ) AS 'DEC Amt'
FROM    dbo.OCRD T0
LEFT JOIN dbo.OINV T1 ON T1.CardCode = T0.CardCode
GROUP BY T0.State1
ORDER BY T0.State1

【问题讨论】:

  • 你应该发布一个 SQL Fiddle
  • 12 次??还有其他方法可以做到这一点......
  • 所以你想为每个状态结果记录添加一列,其中包含一个包含所有相关仓库代码的字符串?您能给我们提供有关表格中状态和卡代码的唯一性的信息吗?到目前为止,从 t1 到 t2 似乎存在一个 n:m 关系,从 t1 到 t0 存在另一个 n:m 关系。这是正确的吗?
  • 您好,托尔斯滕。理想情况下,查询应该输出一个列,显示所有状态、一年中每个月的列以及销售来源的仓库(可能有几个)。状态是独一无二的,因为有 50 个都有单独的条目,即 AA、AK、A​​L、AR 等。不完全确定您在寻找卡码方面的内容。列出的所有客户都将仅是美国客户,并且都具有唯一的卡代码。就 n:m 而言是正确的。谢谢
  • 对不起,我没有看到你的回复。我的问题是:T0 中的一个州有很多记录还是只有一个? T2 中的一个卡码有很多记录还是只有一个? T1 中的一个州有很多记录还是只有一个? T1 中的一个卡码有很多记录还是只有一个? T1 中的状态和卡片代码的一种组合有很多记录还是只有一个?

标签: sql sql-server sap


【解决方案1】:

宁可使用 SQL Pivot:

-- Pivot table with one row and five columns
SELECT 'AverageCost' AS Cost_Sorted_By_Production_Days, 
[0], [1], [2], [3], [4]
FROM
(SELECT DaysToManufacture, StandardCost 
    FROM Production.Product) AS SourceTable
PIVOT
(
AVG(StandardCost)
FOR DaysToManufacture IN ([0], [1], [2], [3], [4])
) AS PivotTable;

【讨论】:

【解决方案2】:

您可以使用条件聚合:

SELECT  [Bill-To-State] =  ISNULL(T0.State1, 'Total'),
        Warehouse = T1.[WhsCode],
        [Jan Amt] = SUM(CASE WHEN DATEPART(MONTH, T1.DocDate) = 1 THEN T1.DocTotal ELSE 0 END),
        [Feb Amt] = SUM(CASE WHEN DATEPART(MONTH, T1.DocDate) = 2 THEN T1.DocTotal ELSE 0 END),
        [Mar Amt] = SUM(CASE WHEN DATEPART(MONTH, T1.DocDate) = 3 THEN T1.DocTotal ELSE 0 END),
        [Apr Amt] = SUM(CASE WHEN DATEPART(MONTH, T1.DocDate) = 4 THEN T1.DocTotal ELSE 0 END),
        [May Amt] = SUM(CASE WHEN DATEPART(MONTH, T1.DocDate) = 5 THEN T1.DocTotal ELSE 0 END),
        [Jun Amt] = SUM(CASE WHEN DATEPART(MONTH, T1.DocDate) = 6 THEN T1.DocTotal ELSE 0 END),
        [Jul Amt] = SUM(CASE WHEN DATEPART(MONTH, T1.DocDate) = 7 THEN T1.DocTotal ELSE 0 END),
        [Aug Amt] = SUM(CASE WHEN DATEPART(MONTH, T1.DocDate) = 8 THEN T1.DocTotal ELSE 0 END),
        [Sep Amt] = SUM(CASE WHEN DATEPART(MONTH, T1.DocDate) = 9 THEN T1.DocTotal ELSE 0 END),
        [Oct Amt] = SUM(CASE WHEN DATEPART(MONTH, T1.DocDate) = 10 THEN T1.DocTotal ELSE 0 END),
        [Nov Amt] = SUM(CASE WHEN DATEPART(MONTH, T1.DocDate) = 11 THEN T1.DocTotal ELSE 0 END),
        [Dec Amt] = SUM(CASE WHEN DATEPART(MONTH, T1.DocDate) = 12 THEN T1.DocTotal ELSE 0 END)
FROM    dbo.OCRD T0
        LEFT JOIN dbo.OINV T1 
            ON T1.CardCode = T0.CardCode
WHERE   T1.DocDate >= DATEADD(YEAR, DATEDIFF(YEAR, 0, GETDATE()), 0)
AND     T1.DocDate < DATEADD(YEAR, DATEDIFF(YEAR, 0, GETDATE()) + 1, 0)
GROUP BY GROUPING SETS ((T0.State1, T1.[WhsCode]), ());

注意,我已使用我首选的方法 Alias = Expression 删除了 deprecated literals for aliases。我更喜欢这个,因为我发现能够立即看到列的名称更容易,而不是必须向右扫描才能找到列的末尾。这完全是个人喜好,如果您对expression AS Alias 更满意,那么您应该使用以下内容,因为它仍然避免使用文字。

SELECT  ISNULL(T0.State1, 'Total') AS [Bill-To-State],
        T1.[WhsCode] AS Warehouse,
        SUM(CASE WHEN DATEPART(MONTH, T1.DocDate) = 1 THEN T1.DocTotal ELSE 0 END) AS [Jan Amt],
        SUM(CASE WHEN DATEPART(MONTH, T1.DocDate) = 2 THEN T1.DocTotal ELSE 0 END) AS [Feb Amt],
        SUM(CASE WHEN DATEPART(MONTH, T1.DocDate) = 3 THEN T1.DocTotal ELSE 0 END) AS [Mar Amt],
        SUM(CASE WHEN DATEPART(MONTH, T1.DocDate) = 4 THEN T1.DocTotal ELSE 0 END) AS [Apr Amt],
        SUM(CASE WHEN DATEPART(MONTH, T1.DocDate) = 5 THEN T1.DocTotal ELSE 0 END) AS [May Amt],
        SUM(CASE WHEN DATEPART(MONTH, T1.DocDate) = 6 THEN T1.DocTotal ELSE 0 END) AS [Jun Amt],
        SUM(CASE WHEN DATEPART(MONTH, T1.DocDate) = 7 THEN T1.DocTotal ELSE 0 END) AS [Jul Amt],
        SUM(CASE WHEN DATEPART(MONTH, T1.DocDate) = 8 THEN T1.DocTotal ELSE 0 END) AS [Aug Amt],
        SUM(CASE WHEN DATEPART(MONTH, T1.DocDate) = 9 THEN T1.DocTotal ELSE 0 END) AS [Sep Amt],
        SUM(CASE WHEN DATEPART(MONTH, T1.DocDate) = 10 THEN T1.DocTotal ELSE 0 END) AS [Oct Amt],
        SUM(CASE WHEN DATEPART(MONTH, T1.DocDate) = 11 THEN T1.DocTotal ELSE 0 END) AS [Nov Amt],
        SUM(CASE WHEN DATEPART(MONTH, T1.DocDate) = 12 THEN T1.DocTotal ELSE 0 END) AS [Dec Amt]
FROM    dbo.OCRD T0
        LEFT JOIN dbo.OINV T1 
            ON T1.CardCode = T0.CardCode
WHERE   T1.DocDate >= DATEADD(YEAR, DATEDIFF(YEAR, 0, GETDATE()), 0)
AND     T1.DocDate < DATEADD(YEAR, DATEDIFF(YEAR, 0, GETDATE()) + 1, 0)
GROUP BY GROUPING SETS ((T0.State1, T1.[WhsCode]), ());

还要注意我已经替换了

WHERE YEAR(T1.DocDate) = YEAR(GETDATE())

WHERE   T1.DocDate >= DATEADD(YEAR, DATEDIFF(YEAR, 0, GETDATE()), 0)
AND     T1.DocDate < DATEADD(YEAR, DATEDIFF(YEAR, 0, GETDATE()) + 1, 0)

这可能看起来很啰嗦,但它允许优化器使用 t1.DocDate 上的任何索引,因为不必对每一行都执行 YEAR 函数。

另一件事是使用

GROUP BY GROUPING SETS ((T0.State1, T1.[WhsCode]), ());

这将添加您的总行,您必须有两个结果集,一个按“(T0.State1, T1.[WhsCode])”分组,一个按“()”分组。在这一总行中,T0.State1T1.[WhsCode] 都将为空,因此我使用 ISNULL(T0.State1, 'Total') 使其在这一行中显示总和。

【讨论】:

  • 感谢您的快速回复。 Warehouse 来自一个名为 OWHS 的表。如何根据您概述的内容声明此表?当我尝试上面的代码时,我得到一个错误(“无效的列名'WhsCode'。”)所以我猜这是由于没有选择表?谢谢
  • 您应该能够再次加入查询 - LEFT JOIN OWHS ON owhs.WhsCode = T1.WhsCode 或任何链接。
猜你喜欢
  • 2012-12-28
  • 1970-01-01
  • 2015-10-20
  • 1970-01-01
  • 1970-01-01
  • 2014-07-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多