sql oracle Union with null values - sql

I have a query on 2 views which when it unions
View X
A B C
2 3
View Y
A B C
3 4
this is my query from the 2 views
select * from view X
UNION
select * from view Y;
the result I had:
A B C
2 3
3 4
the result I wanted (the 2 overrides the null value in view Y # attribute A):
A B C
2 3
2 3 4
how can i obtained that ?

Try this
select nvl(A, lag(A) over (order by rownum)), B, C from (
select A, B, C from X
union
select A, B, C from Y
)
sqlfiddle

here is one answer in oracle
select * from
(select x from tbl1
union
select x from tbl2) t1
,
(select y from tbl1
union
select y from tbl2) t2
,
(select z from tbl1
union
select z from tbl2) t3
where t1.x is not null
order by t1.x desc nulls first;

Related

Count distinct by link on sql?

I'm trying to count distinct by the link between two columns.
Here is the example.
rownum
type
id
1
A
a
2
A
b
3
B
b
4
B
c
5
C
c
6
C
d
If I count distinct by type column, it returns 3. However, what I'd like to do is to consider rownum 2 and 3, 4 and 5 are not distinctive because they got the same value on id column.
To rephrase,
type
array of id
A
a, b
B
b, c
C
c, d
Since A and B got same b, and B and C got same c on their arrays, it would return 1 as a result.
I have no idea where to start. Would appreciate if I can get any hint or something.
Consider below:
you might use STRING_AGG
WITH TMP_TBL AS
(
SELECT 1 AS ROWNUM, 'A' AS TYPE, 'a' AS ID UNION ALL
SELECT 2,'A','b' UNION ALL
SELECT 3,'B','b' UNION ALL
SELECT 4,'B','b' UNION ALL
SELECT 5,'C','c' UNION ALL
SELECT 6,'C','d'
);
SELECT DISTINCT TYPE,N_ID
FROM
(
SELECT TYPE,STRING_AGG(ID)OVER(PARTITION BY TYPE) AS N_ID FROM TMP_TBL
)

Get rows with missing id in Redshift

I have something like
id | name
---|-----
1 | Sarah
3 | Pat
4 | Lea
I'm looking for missing rows. I've tried to use generate_series and a left join but this is something you can't do in Redshift because generate_series is not supported.
Is it possible to do it without temporary table?
EDIT
Finally did with a temporary table (0 to 1_000_000) see answer.
That's probably not optimal. But this is how I did
-- create temporary table
CREATE TABLE series (id INT) SORTKEY(id);
-- insert 0 to 1_000_000
INSERT INTO series WITH seq_0_9 AS
(SELECT 0 AS num
UNION ALL SELECT 1 AS num
UNION ALL SELECT 2 AS num
UNION ALL SELECT 3 AS num
UNION ALL SELECT 4 AS num
UNION ALL SELECT 5 AS num
UNION ALL SELECT 6 AS num
UNION ALL SELECT 7 AS num
UNION ALL SELECT 8 AS num
UNION ALL SELECT 9 AS num),
seq_0_999 AS
(SELECT a.num + b.num * 10 + c.num * 100 AS num
FROM seq_0_9 a,
seq_0_9 b,
seq_0_9 c)
SELECT a.num + b.num * 1000 AS num
FROM seq_0_999 a,
seq_0_999 b
ORDER BY num;
-- Why not
VACUUM series;
-- LEFT OUTER JOIN with table inverted and with the interval
SELECT *
FROM series
LEFT OUTER JOIN other_table ON series.id = other_table.id
WHERE series.id BETWEEN 0 AND 4
ORDER BY series.id;

Sql query to print values starting from column A till column B

New to SQL so looking for help
I'm trying to write a query which would print values starting from column A till the column B excluding the value present in column 'ANS' of second table.
Like here are the two tables X and Y
Table1
A FROM TO
a 6 9
b 3 6
c 0 3
d 2 3
Table2
A ANS
a 7
b 5
c 1
And I want the output as
A ANS
a 6
a 8
a 9
b 3
b 4
b 6
c 0
c 2
c 3
d 2
d 3
I've tried to write something like this but it doesn't work
WITH y(n) AS
(SELECT 1 AS n
FROM dual
UNION ALL
SELECT n + 1 AS n
FROM y, table1 T
WHERE n <= T.TO AND n>= T.FROM )
SELECT * FROM y;
Which prints 5000+ rows (that's why I am not attaching output)
Thanks in advance
After you get all the numbers between from and to with a recursive cte, left join on the generated table and get only those numbers which don't exist in table2 using not exists.
--Get the maximum value of `to` column and generate all numbers between 0 and that value
WITH maxto(maxt) as (SELECT MAX(TO) FROM TABLE1)
,y(n) AS
(SELECT 0 AS n FROM dual
UNION ALL
SELECT n + 1 AS n FROM y WHERE n < (SELECT maxt FROM maxto))
SELECT * FROM
(SELECT t1.a, y.n
FROM y
LEFT JOIN table1 t1 on y.n between t1.from and t1.to
WHERE t1.a IS NOT NULL) x
WHERE NOT EXISTS (SELECT 1 FROM table2 WHERE x.a = a and x.n = ans)
ORDER BY 1,2
Sample demo
WITH y(n) AS
(SELECT level - 1 FROM dual connect by level <= select max(TO- FROM) +2 from table1)
SELECT t1.a, t1.from + y.n FROM table1 t1
JOIN y on 1 = 1
left JOIN table2 on y.n + t1.FROM = t2.ANS and t2.a = t1.a
where y.n < t1.TO-t1.FROM
and t2.ANS is null;
You can use a "hierarchical query" and a MINUS operation and avoid joins altogether. MINUS is easy to understand if you are somewhat familiar with set theory. Generating numbers using hierarchical queries is somewhat unnatural (and may only be available in Oracle, I don't know any other db products), but it is used very often and it works very fast.
I changed the column names to from_n and to_n; I don't remember if "from" and/or "to" are reserved words in Oracle, but why take the risk.
with
table1 ( a, from_n, to_n ) as (
select 'a', 6, 9 from dual union all
select 'b', 3, 6 from dual union all
select 'c', 0, 3 from dual union all
select 'd', 2, 3 from dual
),
table2 ( a, ans ) as (
select 'a', 7 from dual union all
select 'b', 5 from dual union all
select 'c', 1 from dual
)
-- everything above this point is for testing only and can be removed
-- solution (SQL query) begins below
select a, from_n + level - 1 as ans
from table1
connect by level <= 1 + to_n - from_n
and prior a = a
and prior sys_guid() is not null
minus
select a, ans
from table2
;
Output:
A ANS
- ----------
a 6
a 8
a 9
b 3
b 4
b 6
c 0
c 2
c 3
d 2
d 3
11 rows selected

Sum col2 of two tables based on duplicate matching col1

I have 2 tables both structured as (id, views)
Table 1:
id views
A 1
B 2
B 3
C 3
C 4
D 4
Table 2:
id views
C 1
D 3
D 4
E 5
E 7
F 8
I'm looking to sum views of ids that are both in table 1 and 2 (id C and D) in this case so the output would be:
Table 3:
id views
C 8
D 11
You could use the following query in your case :
select a.id,sum(a.views) from ( select * from table1 union table2 ) as a group by id;
select id,sum(views) from (select * from table1 union all select * from table2)a where a.id="C" or a.id="D" group by id;

Oracle advanced union

Is there any advanced Oracle SQL methods to solve this kind of situation?
Simplified:
Two queries returns primary_key_value and other_value.
Both queries always return primary_key_value but other_value might be null.
So how I can union those two queries so that it returns always those rows which has other_value, but if both queries are having other_value = null with same primary key, then only one row should be returned.
I know this is so stupid case. But specifications were like this :)
Example:
First query:
A | B
=======
1 | X
2 |
3 |
4 | Z
Second query:
A | B
=======
1 | Y
2 |
3 | Z
4 |
So result need to be like this:
A | B
=======
1 | X
1 | Y
2 |
3 | Z
4 | Z
You could use analytics:
SQL> WITH q1 AS (
2 SELECT 1 a, 'X' b FROM DUAL UNION ALL
3 SELECT 2 a, '' b FROM DUAL UNION ALL
4 SELECT 3 a, '' b FROM DUAL UNION ALL
5 SELECT 4 a, 'Z' b FROM DUAL
6 ), q2 AS (
7 SELECT 1 a, 'Y' b FROM DUAL UNION ALL
8 SELECT 2 a, '' b FROM DUAL UNION ALL
9 SELECT 3 a, 'Z' b FROM DUAL UNION ALL
10 SELECT 4 a, '' b FROM DUAL
11 )
12 SELECT a, b
13 FROM (SELECT a, b,
14 rank() over(PARTITION BY a
15 ORDER BY decode(b, NULL, 2, 1)) rnk
16 FROM (SELECT * FROM q1
17 UNION
18 SELECT * FROM q2))
19 WHERE rnk = 1;
A B
---------- -
1 X
1 Y
2
3 Z
4 Z
If you want use something really advanced, use model clause http://rwijk.blogspot.com/2007/10/sql-model-clause-tutorial-part-one.html
But, in real life, using such things usually means bad-designed data model
Another way to look at is that you want all possible values from the union of column A then left outer outer join these with the non-null values from column B, thus only showing null in B when there is no non-null value to display.
roughly:
WITH q1 as (whatever),
q2 as (whatever)
SELECT All_A.A, BVals.B
FROM (SELECT DISTINCT A FROM (SELECT A FROM q1 UNION SELECT A FROM q2)) All_A,
(SELECT A,B FROM q1 WHERE B IS NOT NULL
UNION
SELECT A,B FROM q2 WHERE B IS NOT NULL) BVals
WHERE All_A.A = BVals.A (+)
Also pruning the unwanted nulls explicitly could do the same job:
WITH q3 AS (q1_SELECT UNION q2_SELECT)
SELECT A,B
FROM q3 main
WHERE NOT ( B IS NULL AND
EXISTS (SELECT 1 FROM q3 x WHERE main.A = x.A and x.B IS NOT NULL) )