How to combine 2 tables with hard constraint - sql

I got a hard problem in sql that I can't resolve.
I show you it now:
table1
id id2 enter_date exit_date type
1 5 05/05/2021 11/05/2021 A
1 5 11/05/2021 20/05/2021 B
1 . 20/05/2021 30/05/2021 .
table2
id id2 enter_date exit_date type
1 5 08/05/2021 14/05/2021 A
1 5 14/05/2021 20/05/2021 B
1 5 20/05/2021 30/05/2021 C
My table 1 contains all good values but the problem is that she got missing value ( . ) and in my table2, I have every values. But all the values of table2 which are ever in the table 1 are false. But every value of table2 witch are not ever in table 1 are good.
So with my example, it gives me it :
table_final
id id2 enter_date exit_date type
1 5 05/05/2021 11/05/2021 A
1 5 11/05/2021 20/05/2021 B
1 5 20/05/2021 30/05/2021 C
SO I have good date, good type and no missing value.
I tried some thing with union all ... but nothing work.
Thanks for reading me !

This is how I understood the question. Read comments within code
SQL> with
2 -- sample data
3 table1 (id, id2, enter_date, exit_Date, type) as
4 (select 1, 5 , date '2021-05-05', date '2021-05-11', 'A' from dual union all
5 select 1, 5 , date '2021-05-11', date '2021-05-20', 'B' from dual union all
6 select 1, null, date '2021-05-20', date '2021-05-30', null from dual
7 ),
8 table2 (id, id2, enter_date, exit_Date, type) as
9 (select 1, 5 , date '2021-05-08', date '2021-05-14', 'A' from dual union all
10 select 1, 5 , date '2021-05-14', date '2021-05-20', 'B' from dual union all
11 select 1, 5 , date '2021-05-20', date '2021-05-30', 'C' from dual
12 )
13 -- query that returns result you need
14 -- Remove "invalid" rows from TABLE1 (the ones whose ID2 and TYPE aren't null
15 -- (or equal to dot, as you put it)
16 select *
17 from table1
18 where id2 is not null
19 and type is not null
20 union
21 -- From TABLE2, take rows that don't exist in TABLE1 already (matched by ID, ID2 and TYPE)
22 -- where ID2 and TYPE aren't NULL (in TABLE1).
23 select *
24 from table2
25 where (id, id2, type) not in (select id, id2, type
26 from table1
27 where id2 is not null
28 and type is not null
29 );
ID ID2 ENTER_DATE EXIT_DATE T
---------- ---------- ---------- ---------- -
1 5 05/05/2021 11/05/2021 A
1 5 11/05/2021 20/05/2021 B
1 5 20/05/2021 30/05/2021 C
SQL>

Related

How can I select a data from another column from rows that have been selected?

I tried my best to figure and google this out, but couldn't really find a solid answer to it.
The problem I'm facing is that
Table 1:
ID Value 1
1 a
2 b
3 c
Table 2:
ID Value 2
1 4a
3 5b
4 6c
and I'd basically have to select the value from Table 1 that doesn't exist on Table 2 (Thus, 'b')
I can select and identify the ID that I want by using minus function between the tables, but can't seem to figure out a way to call a query to instead call the data.
Use the MINUS as a subquery (i.e. an inline view) (lines #14 - 16):
Sample data:
SQL> with
2 table1(id, value1) as
3 (select 1, 'a' from dual union all
4 select 2, 'b' from dual union all
5 select 3, 'c' from dual
6 ),
7 table2 (id, value2) as
8 (select 1, '4a' from dual union all
9 select 3, '5b' from dual union all
10 select 4, '6c' from dual
11 )
Query begins here:
12 select a.*
13 from table1 a
14 where a.id in (select t1.id from table1 t1
15 minus
16 select t2.id from table2 t2
17 );
ID VALUE1
---------- ----------
2 b
SQL>
Alternatively, use not exists:
<snip>
12 select a.*
13 from table1 a
14 where not exists (select null
15 from table2 b
16 where b.id = a.id
17 );
ID VALUE1
---------- ----------
2 b
SQL>

Merge Missing Dates With The Actual Query

I am working on a query where a database may have all dates with corresponding data or may not have. Data in the
table are as follows:
ID DATE
1 6/1/2021
1 6/2/2021
1 6/3/2021
1 6/4/2021
1 6/5/2021
1 6/8/2021
2 6/4/2021
2 6/5/2021
2 6/8/2021
Expected Output:
ID DATE
1 6/1/2021
1 6/2/2021
1 6/3/2021
1 6/4/2021
1 6/5/2021
1 6/6/2021
1 6/7/2021
1 6/8/2021
2 6/1/2021
2 6/2/2021
2 6/3/2021
2 6/4/2021
2 6/5/2021
2 6/6/2021
2 6/7/2021
2 6/8/2021
So I tried the following query with LEFT JOIN that'll return all required date:
WITH all_dates AS (SELECT TO_DATE('01-JUN-2021') + ROWNUM - 1 AS d FROM dual CONNECT BY ROWNUM <= ADD_MONTHS(TO_DATE('01-JUN-2021'), 12 ) - TO_DATE('01-JUN-2021'))
SELECT T.ID, T.DATE FROM all_dates LEFT JOIN TABLE_HERE t on T.DATE = all_dates.d WHERE all_dates.d <= '08-JUN-2021' AND T.ID ('1', '2') AND T.DATE >= '01-JUN-2021' AND T.DATE <= '08-JUN-2021' ORDER BY all_dates.d;
Unfortunately this only returns data with matching dates, not the missing one (Missing one will be merged with the actual). Is there anything that I require to do to make it work?
To me, it looks as the following query; read comments within code:
SQL> with
2 your (id, datum) as
3 -- your sample data
4 (select 1, date '2021-06-01' from dual union all
5 select 1, date '2021-06-02' from dual union all
6 select 1, date '2021-06-08' from dual union all
7 --
8 select 2, date '2021-06-08' from dual union all
9 select 2, date '2021-06-04' from dual union all
10 select 2, date '2021-06-08' from dual
11 ),
12 calendar as
13 -- you already know how to create a calendar; I'm using only 10 days for simplicity
14 (select date '2021-06-01' + level - 1 datum
15 from dual
16 connect by level <= 10
17 ),
18 ids (id) as
19 -- distinct ID values from your sample table (returns two rows; "1" and "2")
20 (select distinct id from your)
21 -- final query: cross join of calendar and distinct ID values
22 select c.datum, i.id
23 from calendar c cross join ids i
24 order by i.id, c.datum;
The result is
DATUM ID
-------- ----------
01.06.21 1
02.06.21 1
03.06.21 1
04.06.21 1
05.06.21 1
06.06.21 1
07.06.21 1
08.06.21 1
09.06.21 1
10.06.21 1
01.06.21 2
02.06.21 2
03.06.21 2
04.06.21 2
05.06.21 2
06.06.21 2
07.06.21 2
08.06.21 2
09.06.21 2
10.06.21 2
20 rows selected.
SQL>

select data based on the next rows and ids

I have the following table and data,
TABLE - DEAL
ID DEALID
1 DEAL1
2 DEAL2
ALL DEAL2
3 DEAL2
4 DEAL5
5 DEAL5
ALL DEAL6
I want to get only the data as below
ID DEALID
1 DEAL1
4 DEAL5
5 DEAL5
ALL DEAL6
I want to select data based on the value of id column and dealid column.
If the value of id is 'ALL' and corresponding dealid repeats, omit all records with that dealid
Based on sample data you posted, see if this helps. Read comments within code.
SQL> with
2 test (id, dealid) as
3 -- sample data
4 (select '1' , 'deal1' from dual union all
5 select '2' , 'deal2' from dual union all
6 select 'ALL', 'deal2' from dual union all
7 select '3' , 'deal2' from dual union all
8 select '4' , 'deal5' from dual union all
9 select '5' , 'deal5' from dual union all
10 select 'ALL', 'deal6' from dual
11 ),
12 all2 as
13 -- DEALIDs that contain different ID values, and MAX of them is ALL
14 (select dealid
15 from test
16 group by dealid
17 having min(id) <> max(id)
18 and max(id) = 'ALL'
19 )
20 select t.id, t.dealid
21 from test t join all2 a on a.dealid <> t.dealid;
ID DEALI
--- -----
1 deal1
4 deal5
5 deal5
ALL deal6
SQL>

Remove null values from Oracle SQL

I've sql query setup that produces this output:
ID
ID1
ID2
1
123
null
1
234
null
1
456
null
1
null
789
1
null
012
I need the output to be following:
ID
ID1
ID2
1
123
789
1
234
012
1
456
null
Any help will be greatly appreciated.
I have a feeling that this (what you want) should be already done. If that's not possible, see if this helps. Read comments within code.
SQL> with test (id, id1, id2) as
2 -- result produced by current query
3 (select 1, 123, null from dual union all
4 select 1, 234, null from dual union all
5 select 1, 456, null from dual union all
6 select 1, null, '789' from dual union all
7 select 1, null, '012' from dual
8 ),
9 taba as
10 -- ID1 and row ordinal number (for joining purposes)
11 (select id, id1, row_number() over (order by id1) rn
12 from test
13 ),
14 tabb as
15 -- ID2 and row ordinal number (for joining purposes)
16 (select id, id2, row_number() over (order by id2) rn
17 from test
18 )
19 -- join them on ID and RN
20 select a.id, a.id1, b.id2
21 from taba a join tabb b on a.id = b.id and a.rn = b.rn
22 where a.id1 is not null
23 order by a.id, a.id1, b.id2;
ID ID1 ID2
---------- ---------- ---
1 123 012
1 234 789
1 456
SQL>
SELECT ID, ID1, ID2
FROM table1
WHERE ID1 IS NOT NULL
I think that you can use case statement.
look here: Multiple conditions with CASE statements
If after that you question continue, don't worry, call me.

Group the column value based on selective rows for an id

I have a table which have 4 dimensions for a foreignid.
I want to find unique combination based on 2 dimensions.
TABLE1
-----------------------------
ID NAME VALUE TABLE2ID
-----------------------------
1 TYPE 10 1
2 DIR IN 1
3 STATE MA 1
4 COUNT 100 1
5 TYPE 10 2
6 DIR IN 2
7 STATE SA 2
8 COUNT 200 2
9 TYPE 20 3
10 DIR OUT 3
11 STATE MA 3
12 COUNT 300 3
-----------------------------
Here, I want the TABLE2IDs based on the combination of TYPE and DIR rows which is unique.
So, here if you aggregate the row values based on TYPE and DIR you will get
-----------------------------
TYPE DIR TABLE2ID
-----------------------------
10 IN 1
10 IN 2
20 OUT 3
-----------------------------
Note:
The above question is answered
Additional Question related to this.
I have another table which have the count for table2 id based on hour.
I want to group all the count for all hours in a day for unique combination in table1(Don't worry about table 2 structure).
TABLE3
-----------------------------
ID TIME COUNT TABLE2ID
-----------------------------
1 2016101601 10 1
2 2016101602 20 1
3 2016101603 30 1
4 2016101604 40 1
5 2016101601 10 2
6 2016101602 20 2
7 2016101603 30 2
8 2016101604 40 2
9 2016101601 10 3
10 2016101602 20 3
11 2016101603 30 3
12 2016101604 40 3
-----------------------------
Here, I want the output be grouped based on unique value of table 1 according to type and name(regardless of table2id)
----------------------------------
TYPE DIR DATE COUNT
----------------------------------
10 IN 20161016 200
20 OUT 20161016 100
---------------------------------
Use a PIVOT:
Oracle Setup:
CREATE TABLE table1 ( id, name, value, table2id ) AS
SELECT 1, 'TYPE', '10', 1 FROM DUAL UNION ALL
SELECT 2, 'DIR', 'IN', 1 FROM DUAL UNION ALL
SELECT 3, 'STATE', 'MA', 1 FROM DUAL UNION ALL
SELECT 4, 'COUNT', '100', 1 FROM DUAL UNION ALL
SELECT 5, 'TYPE', '10', 2 FROM DUAL UNION ALL
SELECT 6, 'DIR', 'IN', 2 FROM DUAL UNION ALL
SELECT 7, 'STATE', 'SA', 2 FROM DUAL UNION ALL
SELECT 8, 'COUNT', '200', 2 FROM DUAL UNION ALL
SELECT 9, 'TYPE', '20', 3 FROM DUAL UNION ALL
SELECT 10, 'DIR', 'OUT', 3 FROM DUAL UNION ALL
SELECT 11, 'STATE', 'MA', 3 FROM DUAL UNION ALL
SELECT 12, 'COUNT', '300', 3 FROM DUAL;
Query:
SELECT *
FROM ( SELECT name, value, table2id FROM table1 )
PIVOT ( MAX(value) FOR name IN ( 'TYPE' AS type, 'DIR' AS DIR ) );
Output:
TABLE2ID TYPE DIR
-------- ---- ---
1 10 IN
2 10 IN
3 20 OUT
Or as an alternative:
SELECT table2id,
MAX( CASE WHEN name = 'TYPE' THEN value END ) AS type,
MAX( CASE WHEN name = 'DIR' THEN value END ) AS dir
FROM table1
GROUP BY table2id;
You could join two subqueries, one that selects the types and one that selects the dirs for the same id:
SELECT type, dir, a.table2id
FROM (SELECT value AS type, table2id
FROM table1
WHERE name = 'TYPE') a
JOIN (SELECT value AS dir, table2id
FROM table1
WHERE name = 'DIR') b ON a.table2id = b.table2id