I have the below clause in a select statement
ROW_NUMBER() OVER(
PARTITION BY pc
ORDER BY
a DESC, b DESC
) r
How can I apply that function only to the rows which fulfill a certain condition but without filtering the selection at the end in a where clause? .
Sample data:
PC
A
B
pc1
a1
b1
pc1
a2
b2
pc1
a3
b3
Desired output (the condition in this case would be where a2!='a2'):
PC
A
B
R
pc1
a1
b1
1
pc1
a2
b2
null
pc1
a3
b3
2
EDIT: I've tried the below, but it does not start from 1 but from the whole rownum count.
CASE
WHEN condition THEN
ROW_NUMBER() OVER(
PARTITION BY pc
ORDER BY
a, b
)
END r1
Use row_number() within a "case when" statement with a second case statement in the "partition by" as below:
(Case condition when true then ROW_NUMBER() OVER(
PARTITION BY (case condition when true then pc end)
ORDER BY
a DESC, b DESC
)
end)r
Example:
create table sampledata(PC varchar(10), A varchar(10), B varchar(10));
insert into sampledata values('pc1', 'a1', 'b1');
insert into sampledata values('pc1', 'a2', 'b2');
insert into sampledata values('pc1', 'a3', 'b3');
Query:
select *,(Case when A<>'a2' then ROW_NUMBER() OVER(
PARTITION BY (case when A<>'a2' then pc end)
ORDER BY a , b DESC
)
end)r
from sampledata order by a, b desc
Output:
pc
a
b
r
pc1
a1
b1
1
pc1
a2
b2
null
pc1
a3
b3
2
db<fiddle here
If condition is A<>'a1' then
Query:
select *,(Case when A<>'a1' then ROW_NUMBER() OVER(
PARTITION BY (case when A<>'a1' then pc end)
ORDER BY a , b DESC
)
end)r
from sampledata order by a, b desc
Output:
pc
a
b
r
pc1
a1
b1
null
pc1
a2
b2
1
pc1
a3
b3
2
db<fiddle here
I suspect you want a conditional sum:
SUM(CASE WHEN <condition> THEN 1 ELSE 0 END) OVER (
PARTITION BY pc
ORDER BY a DESC, b DESC
) as r
If you want NULL for the non-matching values:
(CASE WHEN <condition>
THEN SUM(CASE WHEN <condition> THEN 1 ELSE 0 END) OVER (
PARTITION BY pc
ORDER BY a DESC, b DESC
)
END) as r
Related
I have a scenario where i should get VAL from table B by joining A and B with the max date of the filled field, e.g:
A:
F1 F2 F3
-- -- --
1 2 t1
2 3 t2
B:
F1 F2 VAL date
---- ---- --- ----------
1 NULL v10 12/30/2020
1 NULL v11 01/31/2020
NULL 2 v20 02/28/2020
NULL 2 v22 03/30/2020
Desired result:
1 2 t1 v11 01/31/2020
2 3 t2 v22 03/30/2020
Thank you in advance.
You can use MAX() and FIRST_VALUE() window functions:
SELECT DISTINCT A.f1, A.f2, A.f3,
FIRST_VALUE(B.VAL) OVER (PARTITION BY COALESCE(B.f1, B.f2) ORDER BY "date" DESC) VAL,
MAX(B."date") OVER (PARTITION BY COALESCE(B.f1, B.f2)) "date"
FROM A INNER JOIN B
ON A.f1 = COALESCE(B.f1, B.f2)
See the demo.
select A.* , maxB.* , B.VAL
from
A
join B
on A.f1 = B.F1
or A.f2 = B.F2
join
(
select
F1, F2 ,VAL , max(date) date
from
B
group by F1,F2
) maxB
on
B.date = maxB.date
and (
maxB.f1 = B.F1
or maxB.f2 = B.F2
)
Try with this
SELECT
R.F1, R.F2, R.F3, R.VAL,R.date
FROM
(
SELECT
A.F1, A.F2, A.F3,
B.VAL,B.date, RANK() OVER(PARTITION BY A.F1,A.F2,A.F3 ORDER BY B.date DESC) as Rank
FROM A
JOIN B ON B.F1 = A.F1 OR B.F2 = A.F1
) R
WHERE
R.Rank = 1
You can use ROW_NUMBER() analytic function within the subquery
WITH AB AS
(
SELECT A.f1, A.f2, B.val, B."date",
ROW_NUMBER() OVER (PARTITION BY NVL(B.f1, B.f2) ORDER BY "date" DESC) AS rn
FROM A
JOIN B
ON A.f1=B.f1 OR A.f1=B.f2
)
SELECT f1,f2,val,"date"
FROM AB
WHERE rn = 1
If ties(equal values) for the date values is the case and all should be included within the result set, then replace ROW_NUMBER() with DENSE_RANK() function.
Demo
Given the following table with 2 columns:
c1 c2
------------
a1 | b1
a1 | b1
a2 | b2
a2 | b3
a3 | b3
I want to return those values from column c2 where the value of c2 column appears multiple times for the same c1 value. I am doing the following SQL query to return the required result:
SELECT DISTINCT ( c2 ) AS c
FROM ( SELECT c1 , c2 , COUNT (*) AS rowcount
FROM table
GROUP BY c1 , c2 HAVING rowcount > 1 )
Result:
c
---
b1
Is there any alternative SQL statement of the above query?
Based on your description, you can use:
select distinct c1
from (select t.*, count(*) over (partition by c2) as cnt
from t
) t
where cnt >= 2;
Based on your sample results:
select c1
from t
group by c1
having count(*) >= 2;
And based on the revised question:
select c2
from t
group by c2
having count(*) >= 2;
Use count in having clause instead of using subquery:-
select c1
from table
group by c1
having count(c2) > 1
Most answers above will work if you want all the values in c1 that appear more than once in the table (even with the same value on c2).
If you want to measure only values of c1 that may have multiple DISTINCT values on c2 you can use:
SELECT c1
FROM table
GROUP BY c1
HAVING COUNT(DISTINCT c2) > 1
Please consider a hive table - TableA as mentioned below.
This basic SQL syntax works fine when we want to get "all" the rows that matches the condition in the where clause. I want to limit the returned rows to a number - say N - for each of the matches of where clause.
Let me explain with an example:
(1)
Consider this table:
TableA
c1 c2
1. a
1 b
1 c
2. d
2. e
2. f
(2) Consider this query:
SELECT c1, c2
FROM TableA
WHERE c1 in (1,2)
(3) As you can imagine, it would produce this result:
Actual Results:
c1 c2
1. a
1 b
1 c
2. d
2. e
2. f
(4)
Desired Result:
c1 c2
1. a
1 b
2. d
2. e
Question: How do I modify the query in #2) to get the desired output mention in #4).
You can use row_number function to do this.
select c1,c2
from (SELECT c1, c2, row_number() over(partition by c1 order by c2) as rnum
FROM TableA
--add a where clause as needed
) t
where rnum <= 2
Only 2 values for c1
SELECT c1, c2 FROM TableA WHERE c1 = 1 ORDER BY c2 LIMIT 2
UNION ALL
SELECT c1, c2 FROM TableA WHERE c1 = 2 ORDER BY c2 LIMIT 2
More than 2 values, use rank()
select c1,c2 from
(
select c1,c2,rank() over (partition by c1 order by c2) as rank
from TableA
) t
where rank < 3;
Table A1 Table B1
A --100 id =1 A --100 id=1
B -- 100 id =2 A -100 id=1
C -- 200 id=3 A - 100 id =1
Need to sum all values from two tables where id =1.
select (SUM(A1.A) + SUM(nvl(B1.A,0))) SUM from A1 a, B1 b where a.id='1' AND b.id='1';
I am getting sum as 600 but it should be 400
Something like this should work.
SELECT id, SUM(A) as Totals FROM
(
SELECT id, A FROM A1
UNION ALL
SELECT id, A FROM B1
) AS tblData
GROUP BY id
You can use:
SELECT COALESCE((SELECT SUM(A) FROM A1 WHERE ID = 1), 0) +
COALESCE((SELECT SUM(A) FROM B1 WHERE ID = 1), 0)
you can do by this way
select sum(A) as total
from
(
select A
from A1 where id = 1
union all
select A
from B1 where id = 1
) t
Here is a method that doesn't use subqueries (although I am not recommending it):
select coalesce(sum(a.a), 0) + coalesce(sum(b.b), 0)
from a full outer join
b
on 1 = 0
where a.id = 1 or b.id = 1;
You used CROSS JOIN ( Cartesian product ) so you get 600..
You can try this to use UNION combine two table.
SELECT SUM(T.Totle)
FROM
(
select SUM(A1.A) Totle from A1 a where a.id='1'
UNION ALL
select SUM(B1.A) Totle from B1 b where b.id='1'
) T
SQLFiddle
I have below table -
ID type group_name creation_date
1 A G1 C1
2 B G2 C2
3 C G2 C3
4 B G1 C4
I want to extract the old type items in each group, but if that type item is latest item in other partition , then i won't extract that.
So, for G1, I will have 2 items A and B where C1 > C4
For G2, I will have 2 items B and C where C2 > C3.
Ideally, B is older for group G1 and C is older for group G2
But i don't want to extract B for G1 since it is latest for G2. Hence
the output should be C only.
Could anyone help how can i achieve this ?
Query:
SELECT DISTINCT
type
FROM (
SELECT type,
rnk,
COUNT( CASE rnk WHEN 1 THEN 1 END ) OVER ( PARTITION BY type ) AS ct
FROM (
SELECT type,
RANK() OVER ( PARTITION BY group_name ORDER BY creation_date DESC ) AS rnk
FROM table_name
)
)
WHERE rnk > 1 AND ct = 0;
Output:
TYPE
----
C