如果列具有特定值,则在 SQL 中聚合/分组表行

发布于 2024-11-02 21:17:51 字数 1608 浏览 1 评论 0原文

我正在使用一个相当复杂的存储过程,它返回 XML(XML 使用样式表进行转换并打印到页面;本质上是 XML 中的 GridView)。我需要将多行(当然具有相同的 ID)聚合为单行仅当特定列的值不是两个特定值之一(在这种情况下,列是未汇总)。

实际上,我需要执行以下操作(以伪代码):

select quoteID, customerName, shippingCharges, description, /*other columns*/
from quotes q
    inner join customers c on q.customerID = c.customerID
where shipDate between @fromDate and @toDate
for xml explicit

if description != "Insurance" and description != "Pickup":
    /*aggregate the rows for that quoteID into one single row
      adding together charges and the like as needed*/  
else:
    /*nothing - okay to have multiple rows*/

我应该如何处理这种类型的逻辑?我的第一个猜测是将所有值放入临时表(或 CTE)中,然后以某种方式检查所有数据以查看是否需要提取和组合行,但对于实际如何完成,我画了一个空白,这通常表明它不是正确的做法...

在 XSL 转换文件中这样做会更好(而且可能更容易吗?)?我的选择仅限于三个选项:

  1. 在存储过程中聚合,保持 XSLT 不变
  2. 在 XSLT 中聚合,保持存储过程不变
  3. 这无法通过当前返回数据的方式来实现(或者如果没有大量数据就无法实现)耗时的解决方法)

编辑

我面临的问题之一是记录通常具有相同的 ID 字段,因此总计结果不正确,因为我正在对整个记录进行求和(哪个计算我想要的字段和我不想要的字段的总计。

例如,一条记录可能是这样的:

1234    Insurance           54.65
1234    Shipping Charge     160.00
1234    Some Other Charge   15.00

我希望最终的结果是这样的:

1234    Shipment    175.00
1234    Insurance   54.65

发生的事情是这样的:

1234    Shipment    229.65
1234    Insurance   229.65

它导致了总数的下降。

我使用的策略是创建一个名为“AggregateData”的 CTE,它按 ID 和描述汇总各种金额和组;这会失败,因为它给出了上述结果(每个描述的总和,因此该值出现两次并在报告中添加两次)。我得到的最接近的是不按描述对其进行分组,而是将其包装在 Max 函数中(是的,我知道这不是一个好主意)。这给了我正确的总数,但描述没有准确地反映,例如一些记录应该是“保险”,但显示的是“装运”。

I am working with a rather hairy Stored Proc which returns XML (the XML is transformed with a stylesheet and printed out to a page; essentially a GridView in XML). I have a requirement to aggregate multiple rows (with the same ID, of course) into a single row only if the value of a particular column is not one of two specific values (in which case the columns are not aggregated).

In effect I need to do the following (in pseudocode):

select quoteID, customerName, shippingCharges, description, /*other columns*/
from quotes q
    inner join customers c on q.customerID = c.customerID
where shipDate between @fromDate and @toDate
for xml explicit

if description != "Insurance" and description != "Pickup":
    /*aggregate the rows for that quoteID into one single row
      adding together charges and the like as needed*/  
else:
    /*nothing - okay to have multiple rows*/

How should I go about handling this type of logic? My first guess would be to put all the values into a temp table (or CTE) and then somehow check all of the data to see if I need to extract and combine rows but I'm drawing a blank as to how that actually is done, which is usually an indicator it's not the correct way of doing it...

Would this be better (and perhaps easier?) to do in the XSL transformation file instead? My choices are limited to three options:

  1. Aggregate in the stored procedure, leave XSLT untouched
  2. Aggregate in the XSLT, leave stored procedure untouched
  3. This can't be achieved with the way the data is being returned currently (or can't be achieved without lots of time-consuming workarounds)

EDIT

One of the issues I'm facing is that the records will usually have the same ID field, and therefore the totals are coming out incorrect because I am summing the whole record (which calculates the total for the field I want and the field that I don't want).

For example a record might be something like:

1234    Insurance           54.65
1234    Shipping Charge     160.00
1234    Some Other Charge   15.00

and I would want the finished result to be like this:

1234    Shipment    175.00
1234    Insurance   54.65

what's happening is this:

1234    Shipment    229.65
1234    Insurance   229.65

and it's throwing the totals off.

The strategy I was using was to create a CTE called "AggregateData" that sums up the various amounts and groups by the ID and the Description; this fails because it gives the above result (sums for each description, so the value appears twice and is added twice on the report). The closest I have gotten is to NOT group it by the Description but instead wrapping it in the Max function (Yes, I know that's not a good idea). This gives me the correct totals but the description isn't accurately being reflected e.g. some records should be "Insurance" but are showing "Shipment" instead.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

零時差 2024-11-09 21:17:51

最简单的方法是编写两个查询并将结果合并

select <columns>
where description not in('Insurance','Pickup')
group by  <some columns)
union all
select <columns>
where description in('Insurance','Pickup')

The easiest way would be to write two queries and union the results

select <columns>
where description not in('Insurance','Pickup')
group by  <some columns)
union all
select <columns>
where description in('Insurance','Pickup')
昔梦 2024-11-09 21:17:51

也许是这样的:

SELECT
  customerName,
  quoteID,
  description = CASE
    WHEN description IN ('Insurance', 'Pickup') THEN description
    ELSE 'Shipment'
  END,
  shippingCharges = SUM(shippingCharges)
FROM quotes q
  INNER JOIN customers c ON q.customerID = c.customerID
GROUP BY
  customerName,
  quoteID,
  CASE
    WHEN description IN ('Insurance', 'Pickup') THEN description
    ELSE 'Shipment'
  END

您一定已经注意到,相同的 CASE 表达式在这里重复了两次。您可以通过使用普通的子选择来避免它:

SELECT
  customerName,
  quoteID,
  description,
  shippingCharges = SUM(shippingCharges)
FROM (
  SELECT
    customerName,
    quoteID,
    description = CASE
      WHEN description IN ('Insurance', 'Pickup') THEN description
      ELSE 'Shipment'
    END,
    shippingCharges = SUM(shippingCharges)
  FROM quotes q
    INNER JOIN customers c ON q.customerID = c.customerID
) s
GROUP BY
  customerName,
  quoteID,
  description

或 CTE:

WITH preparedList AS (
  SELECT
    customerName,
    quoteID,
    description = CASE
      WHEN description IN ('Insurance', 'Pickup') THEN description
      ELSE 'Shipment'
    END,
    shippingCharges = SUM(shippingCharges)
  FROM quotes q
    INNER JOIN customers c ON q.customerID = c.customerID
)
SELECT
  customerName,
  quoteID,
  description,
  shippingCharges = SUM(shippingCharges)
FROM preparedList
GROUP BY
  customerName,
  quoteID,
  description

您可能还想根据需要添加一些其他列。

Maybe something like this:

SELECT
  customerName,
  quoteID,
  description = CASE
    WHEN description IN ('Insurance', 'Pickup') THEN description
    ELSE 'Shipment'
  END,
  shippingCharges = SUM(shippingCharges)
FROM quotes q
  INNER JOIN customers c ON q.customerID = c.customerID
GROUP BY
  customerName,
  quoteID,
  CASE
    WHEN description IN ('Insurance', 'Pickup') THEN description
    ELSE 'Shipment'
  END

You must have noticed that the same CASE expression is repeated twice here. You can avoid it by using an ordinary subselect:

SELECT
  customerName,
  quoteID,
  description,
  shippingCharges = SUM(shippingCharges)
FROM (
  SELECT
    customerName,
    quoteID,
    description = CASE
      WHEN description IN ('Insurance', 'Pickup') THEN description
      ELSE 'Shipment'
    END,
    shippingCharges = SUM(shippingCharges)
  FROM quotes q
    INNER JOIN customers c ON q.customerID = c.customerID
) s
GROUP BY
  customerName,
  quoteID,
  description

or a CTE:

WITH preparedList AS (
  SELECT
    customerName,
    quoteID,
    description = CASE
      WHEN description IN ('Insurance', 'Pickup') THEN description
      ELSE 'Shipment'
    END,
    shippingCharges = SUM(shippingCharges)
  FROM quotes q
    INNER JOIN customers c ON q.customerID = c.customerID
)
SELECT
  customerName,
  quoteID,
  description,
  shippingCharges = SUM(shippingCharges)
FROM preparedList
GROUP BY
  customerName,
  quoteID,
  description

You might also want to add some other columns, as needed.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文