SQL (where in) returns no results - sql

Oracle "table1"
number code
111 aaa
222 bbb
333 aaa
Query
SELECT COUNT(*) AS CNT, CODE
FROM TABLE1
WHERE NUMBER IN (
'444',
'111',
'333',
'222'
) GROUP BY CODE;
Answer
CNT CODE
2 aaa
1 bbb
Need result, please help.
CNT CODE
1 null
2 aaa
1 bbb
I try request with "nvl" but it returns(count) only rows with (null) code, but not count rows.
PS. Sorry for bad English :)

I think you want a left join:
SELECT CODE, COUNT(t1.NUMBER) AS CNT
FROM (SELECT '444' as num FROM DUAL UNION ALL
SELECT '111' as num FROM DUAL UNION ALL
SELECT '333' as num FROM DUAL UNION ALL
SELECT '222' as num FROM DUAL
) x LEFT JOIN
TABLE1 t1
ON t1.NUMBER = x.num
GROUP BY CODE;

Related

How can I select unique and duplicated rows exlude with different values

How can I fetch this table as expected in Oracle. I'm try to do this like below select but its not give me the right result. What I expect is fetch only the unique ones and exclude if these is a record like different values. Sorry for if asked before but I couldn't find it.
SELECT *
FROM ...
WHERE number IN ( SELECT name
FROM (SELECT *
FROM table
WHERE number IN ('Mel','Jose','Kim')
) ds
GROUP BY number
HAVING COUNT (*) = 1)
Current result:
number name
aaa Mel
asd Jose
fsa Jose
xdf Jose
zzz Kim
zzz Kim
Expected result:
aaa Mel
zzz Kim
You're close - I think you were just missing the distinct in the count in your having clause.
E.g.:
WITH your_table AS (SELECT 100 nmbr, 'Mel' NAME FROM dual UNION ALL
SELECT 112 nmbr, 'Jose' NAME FROM dual UNION ALL
SELECT 212 nmbr, 'Jose' NAME FROM dual UNION ALL
SELECT 313 nmbr, 'Jose' NAME FROM dual UNION ALL
SELECT 101 nmbr, 'Kim' NAME FROM dual UNION ALL
SELECT 101 nmbr, 'Kim' NAME FROM dual)
-- end of mimicking data in your table
-- you already have this table, so you would just need the below sql:
SELECT min(nmbr) nmbr,
NAME
FROM your_table
GROUP BY NAME
HAVING COUNT(DISTINCT nmbr) = 1;
NMBR NAME
---------- ----
101 Kim
100 Mel
Just to prove that it doesn't matter whether the nmbr column is of NUMBER or VARCHAR2 datatype:
WITH your_table AS (SELECT 'aaa' nmbr, 'Mel' NAME FROM dual UNION ALL
SELECT 'asd' nmbr, 'Jose' NAME FROM dual UNION ALL
SELECT 'fsa' nmbr, 'Jose' NAME FROM dual UNION ALL
SELECT 'xfd' nmbr, 'Jose' NAME FROM dual UNION ALL
SELECT 'zzz' nmbr, 'Kim' NAME FROM dual UNION ALL
SELECT 'zzz' nmbr, 'Kim' NAME FROM dual)
-- end of mimicking data in your table
-- you already have this table, so you would just need the below sql:
SELECT min(nmbr) nmbr,
NAME
FROM your_table
GROUP BY NAME
HAVING COUNT(DISTINCT nmbr) = 1;
NMBR NAME
---- ----
zzz Kim
aaa Mel
You can do by nested sql with the inner part eliminate repeating ones with respect to id & name, and in the outer part eliminate repeating ones with only name like in the following statement :
SELECT MAX(id),name
FROM (SELECT id,name FROM mytable GROUP BY id, name)
GROUP BY name
HAVING COUNT(1) = 1
ORDER BY MAX(id);
OUTPUT:
ID NAME
----- ------
100 Mel
101 Kim
D e m o 1
exactly the same sql works for your second case :
D e m o 2

Validate information between 2 tables - Oracle SQL

I have 2 tables that I need to validate some information, for example:
Table A (GTM_LICENSE_LINE):
License Nº - License Line Nº
123 - 123_1
123 - 123_2
Table B (GTM_LICENSE_LINE_ITEM):
License Line Nº - Item Nº
123_1 - XXX
However, I need to validate if there are any licenses lines without a Item nº associated (all lines must have only one Item nº).
My expected result would be "1" if the condition is true (all license line have an associated item) or null if the condition is false. I'm trying to use LEFT JOIN w/ GROUP BY but it's not working for me.
SELECT u.GTM_LICENSE_LINE_GID
FROM GTM_LICENSE_LINE I
LEFT JOIN GTM_LICENSE_LINE_ITEM U
ON I.LICENSE_LINE_GID = U.GTM_LICENSE_LINE_GID
WHERE i.LICENSE_GID = 'ELEB.L001'
AND U.GTM_LICENSE_LINE_GID is null
GROUP BY U.GTM_LICENSE_LINE_GID
HAVING COUNT(*) > 0
How can I do this using Oracle SQL? Any suggestions?
Thanks
I think you're probably after something like this:
WITH table1 AS (SELECT 123 License_num, '123_1' license_line_num FROM dual UNION ALL
SELECT 123 License_num, '123_2' license_line_num FROM dual UNION ALL
SELECT 456 License_num, '456_1' license_line_num FROM dual UNION ALL
SELECT 456 License_num, '456_2' license_line_num FROM dual),
table2 AS (SELECT '123_1' license_line_num, 'XXX' item_num FROM dual UNION ALL
SELECT '456_1' license_line_num, 'YYY' item_num FROM dual UNION ALL
SELECT '456_2' license_line_num, 'ZZZ' item_num FROM dual)
SELECT t1.license_num,
t1.license_line_num,
MIN(CASE WHEN t2.license_line_num IS NULL THEN 0 ELSE 1 END) OVER (PARTITION BY t1.license_num) all_lines_present
FROM table1 t1
LEFT OUTER JOIN table2 t2 ON t1.license_line_num = t2.license_line_num
ORDER BY t1.license_num, t1.license_line_num;
LICENSE_NUM LICENSE_LINE_NUM ALL_LINES_PRESENT
----------- ---------------- -----------------
123 123_1 0
123 123_2 0
456 456_1 1
456 456_2 1
I'm assuming here that there is a unique constraint on table2 where you can have at most one row for each license_line_num.
This works by outer joining the second table to the first (which shouldn't produce any duplicate lines). Then we use a conditional aggregate function (in this case, MIN) to determine that if there is a value from the second table present, we output a 1 otherwise a 0 for each row, before finding the lowest value.
That way, if any of the rows is missing an item row, the lowest value across all rows for each license_num will be 0.
ETA: If you just want a single row per license_num, you can just use a conditional aggregate function instead, e.g.:
WITH table1 AS (SELECT 123 License_num, '123_1' license_line_num FROM dual UNION ALL
SELECT 123 License_num, '123_2' license_line_num FROM dual UNION ALL
SELECT 456 License_num, '456_1' license_line_num FROM dual UNION ALL
SELECT 456 License_num, '456_2' license_line_num FROM dual),
table2 AS (SELECT '123_1' license_line_num, 'XXX' item_num FROM dual UNION ALL
SELECT '456_1' license_line_num, 'YYY' item_num FROM dual UNION ALL
SELECT '456_2' license_line_num, 'ZZZ' item_num FROM dual)
SELECT license_num,
CASE WHEN all_lines_present = 1 THEN 1 END all_lines_present
FROM (SELECT t1.license_num,
MIN(CASE WHEN t2.license_line_num IS NULL THEN 0 ELSE 1 END) all_lines_present
FROM table1 t1
LEFT OUTER JOIN table2 t2 ON t1.license_line_num = t2.license_line_num
GROUP BY t1.license_num)
ORDER BY license_num;
LICENSE_NUM ALL_LINES_PRESENT
----------- -----------------
123
456 1

How to determine which record wasn't found in an IN clause

Say I have a SQL statement:
SELECT *
FROM MY_TABLE
WHERE MY_FIELD IN ('AAA','BBB','CCC', 'DDD');
and my table was:
ID FIELD1
1 AAA
2 CCC
3 DDD
4 FFF
The above sql statement would give me the 3 records in the database.
My question is how can I alter my SQL statement to find which record it didn't find? (i.e. Show me that BBB didnt match)
You need a LEFT JOIN, NOT IN, or NOT EXISTS for that:
SELECT v.*
FROM (SELECT 'AAA' as f FROM DUAL UNION ALL
SELECT 'BBB' as f FROM DUAL UNION ALL
SELECT 'CCC' as f FROM DUAL UNION ALL
SELECT 'DDD' as f FROM DUAL
) v LEFT JOIN
MY_TABLE t
ON v.f = t.my_field
WHERE t.my_field IS NULL;
SELECT *
FROM MY_TABLE
WHERE MY_FIELD NOT IN ('AAA','BBB','CCC', 'DDD');

How to calculate percentage in oracle sql

I have a table in which I have multiple IDs which can have a value or 0. The IDs come from different sources so I would like to know what is the percentage of IDs with the value 0 as a percentage of total IDs, for each source file.
Sample Data:
ID Source
1 aaa
0 aaa
2 bbb
0 ccc
3 ccc
0 ccc
5 aaa
0 bbb
6 bbb
7 bbb
I need to display Output like:
CountOfIDs0 TotalIDs Source PercentageIDs0
2 3 ccc 66.6%%
1 3 aaa 33.3%%
1 4 bbb 25%
Thanks!
If you want a result like 66.6% rather than 66.7%, you would use trunc() rather than round() (although the latter is probably better). And you need to round a/b to three decimal places, so there is one left after you multiply by 100.
Then, you can have both counts in one query, and you can add the percentage calculation also in the same query.
select count(case when propkey = 0 then 1 end) countid0,
count(propkey) totalidcount,
source,
to_char(round(count(case when properkey = 0 then 1 end)/count(properkey), 3)*100)
|| '%' percentageids0
from......
Apply round function.
select count(id) as TotalIDs ,Source, sum(case when id=0 then 1 end) countid0,
to_char((sum(case when id=0 then 1 end)/count(id))*100)||'%' as PercentageIDs0
from Table1 group by Source
For Unique record you have to use DISTINCT Query
I would do it that way:
With MyRows AS (
SELECT 1 ID, 'aaa' SOURCE FROM DUAL UNION ALL
SELECT 0, 'aaa' FROM DUAL UNION ALL
SELECT 2, 'bbb' FROM DUAL UNION ALL
SELECT 0, 'ccc' FROM DUAL UNION ALL
SELECT 3, 'ccc' FROM DUAL UNION ALL
SELECT 0, 'ccc' FROM DUAL UNION ALL
SELECT 5, 'aaa' FROM DUAL UNION ALL
SELECT 0, 'bbb' FROM DUAL UNION ALL
SELECT 6, 'bbb' FROM DUAL UNION ALL
SELECT 7, 'bbb' FROM DUAL
)
SELECT
DISTINCT SOURCE,
SUM(CASE WHEN ID = 0 THEN 1 ELSE 0 END) OVER (PARTITION BY SOURCE) ZERO_IDS,
COUNT(ID) OVER (PARTITION BY SOURCE) TOTAL_IDS,
(100 * SUM(CASE WHEN ID = 0 THEN 1 ELSE 0 END) OVER (PARTITION BY SOURCE))/(COUNT(ID) OVER (PARTITION BY SOURCE)) PERCENTAGE
FROM MyRows
;
I calculated percentage of values in a column by using below query
Select A.,B., to_char((A.count_service/B.count_total)*100)||'%' from
(Select type_cd, count(type_cd) as count_type
from table1
group by type_cd) A
cross join
(Select count(type_cd) as count_total
from table1) B ;
select Source,
ROUND(100*number/sum(number) OVER (PARTITION BY p),2) as percentage,
sum(number) OVER (PARTITION BY p) as total
from(
select 1 p,
Source ,
count(Source) number
from declaration_assessment_result
GROUP by Source
)x

oracle SQL select/join with many-to-one and nulls

I'm having trouble crafting an Oracle SQL query that returns the results I seek. It's possible that what I'm trying to do isn't possible.
For a given code in table one, if the code exists in table two and ANY of the flags are "1", then the status should be "1" in the query results. Otherwise, the status should be "0". If the code doesn't exist at all in table 2, then the status should be null.
tab1
------------
id,code
------------
1,ABC
2,DEF
3,GHI
4,JKL
5,MNO
6,PQR
7,STU
tab2
------------
id,code,flag
------------
1,ABC,0
2,ABC,0
3,DEF,1
4,DEF,1
5,GHI,0
6,GHI,1
7,JKL,1
8,JKL,0
9,MNO,0
10,PQR,1
(query?)
result
------------
id,code,status
------------
1,ABC,0
2,DEF,1
3,GHI,1
4,JKL,1
5,MNO,0
6,PQR,1
7,STU,null
So far, the only query I've been able to come up with is this, which doesn't give the right results in the status column...
select tab1.*, (select * from (
select flag from tab2 where tab2.code = code order by flag desc)
where rownum <=1) as status from tab1;
... status is always "1", which is incorrect.
I'm thinking that instead of using order by and selecting the first result, it might be possible to instead count the number of "1" flags for each code, but I'm not sure if that would work.
My first inclination is to use a subselect:
select t1.*,
(select max(t2.flag)
from table2 t2
where t2.code = t1.code
) as t2flag
from table1 t1;
You can also phrase this as a left join with an aggregation:
select t1.*, t2.flag
(select max(t2.flag)
from table2 t2
where t2.code = t1.code
) as t2flag
from table1 t1 left join
(select t2.code, max(t2.flag) as flag
from table2 t2
group by t2.code
) t2
on t2.code = t1.code;
Both these methods are assuming that flag is either 0 or 1, as in your question.
I'd use a LEFT JOIN:
select t1.id, max(t1.code) code, max(t2.flag) status
from table1 t1
left join table2 t2 on t1.code=t2.code
group by t1.id
Assuming that 0 and 1 are the only two flags, what about something like:
with tab1 as (select 1 id, 'ABC' code from dual union all
select 2 id, 'DEF' code from dual union all
select 3 id, 'GHI' code from dual union all
select 4 id, 'JKL' code from dual union all
select 5 id, 'MNO' code from dual union all
select 6 id, 'PQR' code from dual union all
select 7 id, 'STU' code from dual),
tab2 as (select 1 id, 'ABC' code, 0 flag from dual union all
select 2 id, 'ABC' code, 0 flag from dual union all
select 3 id, 'DEF' code, 1 flag from dual union all
select 4 id, 'DEF' code, 1 flag from dual union all
select 5 id, 'GHI' code, 0 flag from dual union all
select 6 id, 'GHI' code, 1 flag from dual union all
select 7 id, 'JKL' code, 1 flag from dual union all
select 8 id, 'JKL' code, 0 flag from dual union all
select 9 id, 'MNO' code, 0 flag from dual union all
select 10 id, 'PQR' code, 1 flag from dual)
select t1.id,
t1.code,
t2.flag status
from tab1 t1
left join (select code,
max(flag) flag
from tab2
group by code) t2
on (t1.code = t2.code);
ID CODE STATUS
---------- ---- ----------
5 MNO 0
6 PQR 1
2 DEF 1
1 ABC 0
3 GHI 1
4 JKL 1
7 STU
Maybe I'm missing something, but it seems to be as simple as this:
select tab1.id, tab1.code, max(tab2.flag) status
from tab1
left join tab2 on tab1.code = tab2.code
group by tab1.id, tab1.code
order by tab1.id;
A sample SQL Fiddle gives the desired result:
| id | code | status |
|----|------|--------|
| 1 | ABC | 0 |
| 2 | DEF | 1 |
| 3 | GHI | 1 |
| 4 | JKL | 1 |
| 5 | MNO | 0 |
| 6 | PQR | 1 |
| 7 | STU | (null) |
SELECT ID,
CODE,
MAX( STATUS)
FROM
(SELECT DISTINCT T1.ID,
T1.CODE,
FLAG AS STATUS
FROM T1
LEFT JOIN T2
ON T1.CODE = T2.CODE
)
GROUP BY ID,
CODE;
This gives result as you asked:
SELECT tab1.id,tab1.code,max(tab2.flag) as Status
FROM tab1 LEFT JOIN tab2
ON tab1.code=tab2.code
GROUP BY tab2.code
ORDER BY tab1.id;