重写SQL查询以返回每个数据集的行

时间:2016-05-02 20:12:16

标签: sql sql-server dataset

我有下表用于学生的费用支付

[fee_id]         INT             
[user_id]        INT             
[payment]        DECIMAL (18, 2) 
[date]           DATETIME        
[fee_remaining]  DECIMAL (18, 2) 
[year]           INT             
[payment_method] NVARCHAR (50)
[fee_required]   DECIMAL (18, 2)

这是我目前的查询,显示已支付,尚未支付或部分支付年度费用的学生人数

SELECT DISTINCT
  (SELECT COUNT(*) AS Expr1
   FROM fee_payments
   WHERE (fee_remaining = 0)
     AND (YEAR = @year)) AS Fully_Paid,

  (SELECT COUNT(*) AS Expr1
   FROM fee_payments
   WHERE (fee_remaining = fee_required)
     AND (YEAR = @year)) AS Unpaid,

  (SELECT COUNT(*) AS Expr1
   FROM fee_payments
   WHERE (fee_remaining > 0)
     AND (YEAR = @year)
     AND (fee_remaining <> fee_required)) AS Partially_Paid
FROM fee_payments AS fee_payments_1

这是我的输出

Fully_Paid | Unpaid | Partially_Paid
-------------------------------------
    8      |   1    |       5

是否可以将输出显示如下?

Status          | Total
----------------------------
Fully Paid      |   8
Unpaid          |   1
Partially Paid  |   5

非常感谢任何帮助

4 个答案:

答案 0 :(得分:3)

使用case表达式为每行指定所需状态,并为计算列指定group by

select status, count(*) as total
from (
SELECT 
case when fee_remaining = 0 then 'fully_paid'
     when fee_remaining <> fee_required then 'partially_paid' 
     when fee_remaining = fee_required then 'unpaid' 
end as status
FROM fee_payments
WHERE YEAR = @year) t
group by status

另请注意,假设fee_remaining和fee_required为非空值。如果它们可以是null,请在比较时使用coalesce来处理它们。

答案 1 :(得分:0)

因此,如果完全将您的查询重组为更高效的内容,例如kvp's answer,您可以UNION每个结果,而不是将它们作为子查询使用:< / p>

SELECT 'Fully Paid' AS Status, COUNT(*) AS Total
FROM fee_payments
WHERE (fee_remaining = 0) AND (YEAR = @year)
UNION
SELECT 'Unpaid', COUNT(*)
FROM fee_payments
WHERE (fee_remaining = fee_required) AND (YEAR = @year)
UNION 
SELECT 'Partially Paid', COUNT(*)
FROM fee_payments
WHERE (fee_remaining > 0) AND (YEAR = @year) AND (fee_remaining <> fee_required)

答案 2 :(得分:0)

您的代码似乎每年有多行。似乎最后一行是最有用的,所以我想这样的事情:

select sum(case when fee_remaining = 0 then 1 else 0 end) as FullyPaid,
       sum(case when fee_remaining < fee_required then 1 else 0 end) as PartiallyPaid,
       sum(case when fee_remaining = fee_required then 1 else 0 end) as Unpaid      
from (select fp.*,
             row_number() over (partition by user_id order by date desc) as seqnum
      from fee_payments fp
      where YEAR = @year
     ) fp
where seqnum = 1;

答案 3 :(得分:0)

SELECT 'Fully Paid' as Status, COUNT(*) AS Total
   FROM fee_payments
   GROUP BY year
   WHERE fee_remaining = 0
     AND YEAR = @year
UNION ALL
SELECT 'Unpaid' as Status, COUNT(*) AS Total
   FROM fee_payments
   GROUP BY year
   WHERE fee_remaining = fee_required
     AND YEAR = @year
UNION ALL
SELECT 'Partially Paid' as Status, COUNT(*) AS Total
   FROM fee_payments
   GROUP BY year
   WHERE fee_remaining > 0
     AND YEAR = @year
     AND fee_remaining <> fee_required