将每个数据集的 SQL 查询重写为 return 行

Rewrite SQL query to return rows for each dataset

我有以下table学生费用支付

[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

如有任何帮助,我们将不胜感激

使用 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处理

因此,如果不完全将您的查询重组为更高效的查询,例如 ,您可以 UNION 每个结果,而不是将它们分别用作子查询:

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)

您的代码似乎每年不止一行。似乎最后一行信息量最大,所以我在想这样的事情:

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;
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