我有两个简单的表格:
OrderStatus
和OrderStage
分别具有OrderStatusID
和OrderStageID
的主键整数列。每个表返回大约5行。
我要做的是创建一个SELECT语句,它计算每个OrderStatusID和OrderStageID组合的订单数。这是一个例子:
SELECT
COUNT(OrderID)
FROM
Order
WHERE
OrderStatusID = '1' and OrderStageID = '1'
SELECT
COUNT(OrderID)
FROM
Order
WHERE
OrderStatusID = '1' and OrderStageID = '2'
......
SELECT
COUNT(OrderID)
FROM
Order
WHERE
OrderStatusID = '4' and OrderStageID = '5'
我必须编写5x5 SQL语句来计算每种可能组合中的订单数量。如果有人在OrderStatus
或OrderStage
表中添加了更多行,那么我将不得不重新访问此代码以添加新的组合。
此数据的最终呈现将位于网页上的“树”中,与Outlook在邮件面板中显示收件箱,已发送邮件,已删除等电子邮件的计数方式非常相似。我在我的网页上使用ColdFusion。如果我使用GROUP BY语句来获取数据,那么我如何在ColdFusion中单独显示每个结果行? <cfquery group="">
会有效吗?
对于给定OrderStatusID和OrderStageID组合的Order表中没有行,它应返回0或NULL。这就是我为每种可能的组合使用单独的SELECT语句的原因。
答案 0 :(得分:7)
我确信有更简单的方法可以为SQL Server 2012编写它,但基本上可以使用CROSS JOIN
来获取状态和阶段(即25行)的所有可能组合。 然后将外部联接返回orders
以获取每个组合的计数:
**通常最好避免使用order
等关键字作为表名
SELECT osg.OrderStageID, ost.OrderStatusID, COUNT(o.OrderID) AS TotalOrders
FROM orderStage osg CROSS JOIN orderStatus ost
LEFT JOIN [order] o ON o.OrderStageID = osg.OrderStageID
AND o.OrderStatusID = ost.OrderStatusID
GROUP BY osg.OrderStageID, ost.OrderStatusID
注意:请务必查看CROSS JOIN的运作方式。
答案 1 :(得分:2)
如果要显示不存在的0
,可以创建一个包含所有组合的驱动程序表,并加入到该表:
SELECT driver.*,SUM(CASE WHEN o.OrderStatusID IS NOT NULL THEN 1 ELSE 0 END)AS OrderCount
FROM (SELECT *
FROM (SELECT DISTINCT OrderStatusID FROM Orders) a
,(SELECT DISTINCT OrderStageID FROM Orders) b
) driver
LEFT JOIN Orders o
ON driver.OrderStatusID = o.OrderStatusID
AND driver.OrderStageID = o.OrderStageID
GROUP BY driver.OrderStatusID
, driver.OrderStageID
演示:SQL Fiddle
答案 2 :(得分:1)
在回答这些类型的问题时,我喜欢在tempdb中创建一个示例表。
--
-- Create test table
--
-- Just toss away code
USE tempdb;
GO
-- Create a simple table
CREATE TABLE my_orders
(
my_orderstatus_id int,
my_orderstage_id int
);
GO
如果你没有看过Jeff Moden的计数表,你应该这样做。它们是以关系代数方式进行循环的快速方法。我正在加载组合(1..5)(1..5)次数和(6..10)(6..10)两次。 go之后的数字告诉我们运行TSQL的次数。
--
-- Load test table
--
-- Create some data (1-5) x 4 counts
;
WITH cteTally1 (my_number1) AS
(
SELECT
ROW_NUMBER() OVER(ORDER BY a.name) AS my_number
FROM
sys.objects a
CROSS JOIN
sys.objects b
),
cteTally2 (my_number2) AS
(
SELECT
ROW_NUMBER() OVER(ORDER BY a.name) AS my_number
FROM
sys.objects a
CROSS JOIN
sys.objects b
)
INSERT INTO my_orders
SELECT my_number1, my_number2
FROM cteTally1 T1 CROSS JOIN cteTally2 T2
WHERE
(T1.my_number1 > 0 AND T1.my_number1 <= 5 ) AND
(T2.my_number2 > 0 AND T2.my_number2 <= 5 );
GO 4
-- Create some data (6-10) x 2 counts
;
WITH cteTally1 (my_number1) AS
(
SELECT
ROW_NUMBER() OVER(ORDER BY a.name) AS my_number
FROM
sys.objects a
CROSS JOIN
sys.objects b
),
cteTally2 (my_number2) AS
(
SELECT
ROW_NUMBER() OVER(ORDER BY a.name) AS my_number
FROM
sys.objects a
CROSS JOIN
sys.objects b
)
INSERT INTO my_orders
SELECT my_number1, my_number2
FROM cteTally1 T1 CROSS JOIN cteTally2 T2
WHERE
(T1.my_number1 >= 6 AND T1.my_number1 <= 10 ) AND
(T2.my_number2 >= 6 AND T2.my_number2 <= 10 );
GO 2
-- Show the data
SELECT * FROM my_orders;
最后但并非最不重要的是,一个简单的分组将为您提供每个组合的计数。
--
-- Simple group by will suffice
--
SELECT
my_orderstatus_id,
my_orderstage_id,
COUNT(*) as number
FROM my_orders
GROUP BY
my_orderstatus_id,
my_orderstage_id;
GO
输出的快速屏幕截图:
这应该可以解答您的特定问题。但如果我确实错误地提出要求,请回复。
您现在更改了初始要求。我们在管理层中称之为 SCOPE CHANGE 。
如果您知道组合总是10 x 10,请创建矩阵表或公用表表达式,这样无论匹配如何,您都将始终拥有组合。
通过相应的方式将简单组扩展为左连接到数据和组/顺序。
--
-- Report Query
--
-- For missing records
;
WITH cteTally1 (my_number1) AS
(
SELECT
ROW_NUMBER() OVER(ORDER BY a.name) AS my_number
FROM
sys.objects a
CROSS JOIN
sys.objects b
),
cteTally2 (my_number2) AS
(
SELECT
ROW_NUMBER() OVER(ORDER BY a.name) AS my_number
FROM
sys.objects a
CROSS JOIN
sys.objects b
),
cteMissingCombos (my_orderstatus_id, my_orderstage_id) AS
(
SELECT T1.my_number1, T2.my_number2
FROM cteTally1 T1 CROSS JOIN cteTally2 T2
WHERE T1.my_number1 < 11 AND T2.my_number2 < 11
)
-- Return null if no records, use coalesce if you want 0
SELECT
C.my_orderstatus_id,
C.my_orderstage_id,
COUNT(O.my_orderstatus_id) as number
FROM
cteMissingCombos as C LEFT JOIN my_orders as O
ON
C.my_orderstatus_id = O.my_orderstatus_id AND
C.my_orderstage_id = O.my_orderstage_id
GROUP BY
C.my_orderstatus_id,
C.my_orderstage_id
ORDER BY
C.my_orderstatus_id,
C.my_orderstage_id
GO
下面的输出显示我们没有1 x 6到10的组合。因此