Home > Net >  is there a function in sql to find second minimum in table, which then used in case
is there a function in sql to find second minimum in table, which then used in case

Time:10-11

For example, there are two tables, and in one - prices with articles, and another table - checks, some articles in checks, and quantity of article

TABLE checks

checks art quantity
1check 1toy 2
1check 1toy 5
1check 1toy 1
1check 2toy 1
1check 4toy 3
2check 2toy 1
2check 1toy 2

TABLE articles

art price
1toy 2.00
2toy 2.50
3toy 1.50
4toy 6.00
1toy 2.50
1toy 3.00

and i need to count the sum of sales of 1check,where i need to take the second minimum of price if the articles repeat. for 1toy in 1check the price have to be 2.5.- for sum (quantity*price) i try to write a code - but i finally confused. help please

SELECT
    a.check,
    Sump
FROM
    (
        SELECT
            price2,
            Case
                WHEN COUNT( a.art ) > 1 THEN
                    SUM( a.quantity * a.price ) 
                ELSE
                    SUM( a.quantity * price2 )
            END AS sump,
            a.art,
            a.check
        FROM
            checks AS a
            INNER JOIN
            (
                SELECT
                    art,
                    price,
                    LEAD( price, 1 ) OVER (
                        PARTITION BY art
                        ORDER BY price ASC
                    ) AS price2
            FROM
                prices
            ) AS b on a.art = b.art
        WHERE
            a.quantity > 0
        GROUP BY
            a.checks,
            a.art,
            price2
    )
WHERE
    a.checks = '1check' 

CodePudding user response:

You may use the ROW_NUMBER() and COUNT window functions as the following:

SELECT T.checks, T.art, SUM(T.quantity * D.price) sump
  FROM
  checks T JOIN
  ( 
    SELECT art, price,
       COUNT(*) OVER (PARTITION BY art) cn,
       ROW_NUMBER() OVER (PARTITION BY art ORDER BY price) rn
    FROM articles
  ) D
ON T.art = D.art
WHERE (D.cn = 1 OR D.rn = 2) AND T.checks = '1check'
GROUP BY T.checks, T.art
ORDER BY T.checks, T.art

The WHERE (D.cn = 1 OR D.rn = 2) ensures that the returned price is the second minimum (rn=2) or it's only the existed price (cn=1).

The output according to your provided data:

CHECKS ART SUMP
1check 1toy 20
1check 2toy 2.5
1check 4toy 18

See a demo on Oracle 11g.

CodePudding user response:

We use dense_rank() to find the second lowest price in the case count(*) > 1. Then we merge the tables, group by art and total the sales.

with a  as (
select  art
       ,price
from   
        (
        select   a.*
                ,dense_rank() over(partition by art order by price) as dns_rnk
                ,count(*) over(partition by art)                    as cnt
        from    articles a
        ) a 
where   cnt > 1 and dns_rnk = 2
or      cnt = 1 
          )

  
select   art
        ,sum(quantity)*price as total
from     a left join checks c using(art)
group by art, price
order by art
ART TOTAL
1toy 100
2toy 10
3toy null
4toy 18

Fiddle

  •  Tags:  
  • sql
  • Related