简体   繁体   中英

Complex SQL query with group by and having

I am having a table orders

orders (
id  int unsigned not null,
fcr_date  TIMESTAMP,
completion_date TIMESTAMP,
factory_no  varchar(255),
vendor_no  varchar(255))

Please ignore the data type typos if any.

I want to write a sql query that helps me filter the data per vendor factory. The data to fetch includes the number of orders per vendor factory(a unique group of vendor_no, factory_no), vendor_no, factory_no and the percentage of orders for which fcr_date is greater than completion_date(so percentage = number of orders where fcr_date is greater than completion date / count of orders). After that i need to filter the data where percentage is greater than say 20%.

I wrote the following query:

SELECT  vendor_no As vendor,
        factory_no As factory,
        COUNT(1) as count,
        SUM(CASE WHEN fcr_date > completion_date THEN 1 ELSE 0 END) as filter_orders,
    ROUND(filter_orders / count * 100, 4) as  percent  
FROM    @orders
GROUP BY vendor_no,
        factory_no
HAVING percent>20

but postgresql complains that it needs to have a column called percent in table to filter the results based on that. Any help is appreciated.

Thanks.

Change it to:

HAVING ROUND(filter_orders / count * 100, 4) > 20

Because percent isn't an actual column, you need to give it the calculation to perform the filter.

Edit

OK, looking at this further, you've got at least two ways to write this: the one I'd recommend is the first, which involves wrapping in a sub-query (as someone already suggested):

Option 1

SELECT  vendor As vendor,
        factory As factory,
        [count],
        ROUND(filter_orders / count * 100, 4) as  [percent]
FROM
(
    SELECT  vendor_no As vendor,
            factory_no As factory,
            COUNT(1) as count,
            SUM(CASE WHEN fcr_date > completion_date THEN 1 ELSE 0 END) as filter_orders
    FROM    @orders
    GROUP BY vendor_no,
            factory_no
) AS a
WHERE ROUND(filter_orders / count * 100, 4) > 20

Option 2

SELECT  vendor_no As vendor,
        factory_no As factory,
        COUNT(1) as count,
        SUM(CASE WHEN fcr_date > completion_date THEN 1 ELSE 0 END) as filter_orders,
        ROUND(SUM(CASE WHEN fcr_date > completion_date THEN 1 ELSE 0 END) / count(1) * 100, 4) as  [percent]
FROM    @orders
GROUP BY vendor_no,
        factory_no
HAVING ROUND(SUM(CASE WHEN fcr_date > completion_date THEN 1 ELSE 0 END) / count(1) * 100, 4) > 20

Wrap your query with an outer filtering query:

SELECT * FROM (
    SELECT  vendor_no As vendor,
            factory_no As factory,
            COUNT(1) as count,
            SUM(CASE WHEN fcr_date > completion_date THEN 1 ELSE 0 END) as filter_orders,
        ROUND(filter_orders / count * 100, 4) as  percent  
    FROM    @orders
    GROUP BY vendor_no,
            factory_no
) x
WHERE percent>20

I'm pretty sure you can't use aliases (like percent) in having clauses or group by clauses. And by "pretty" I mean Oracle won't let me use aliases in having/group by clauses...not sure about other vendors.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM