Oracle SQL grouping based on value in blob field - sql

This may not be possible
I have a table with a blob which contains XML and I want to get a count based on the content of the blob is there a way to do it in one query instead of doing
select count(*)
from MyTable
where dbms_lob.instr(bitstream, utl_raw.CAST_TO_RAW('ObjA'), 1, 1) > 0
select count(*)
from MyTable
where dbms_lob.instr(bitstream, utl_raw.CAST_TO_RAW('ObjB'), 1, 1) > 0
select count(*)
from MyTable
where dbms_lob.instr(bitstream, utl_raw.CAST_TO_RAW('ObjC'), 1, 1) > 0
select count(*)
from MyTable
where dbms_lob.instr(bitstream, utl_raw.CAST_TO_RAW('ObjD'), 1, 1) > 0
select count(*)
from MyTable
where dbms_lob.instr(bitstream, utl_raw.CAST_TO_RAW('ObjE'), 1, 1) > 0

Would something like this do?
Store values you're looking for into a CTE, and then join that CTE to your table.
WITH
temp (obj)
AS
(SELECT *
FROM TABLE (sys.odcivarchar2list ('ObjA',
'ObjB',
'ObjC',
'ObjD',
'ObjE')))
SELECT t.obj, COUNT (*)
FROM mytable e
JOIN temp t
ON DBMS_LOB.INSTR (bitstream,
UTL_RAW.cast_to_raw (t.obj),
1,
1) > 0
GROUP BY t.obj;

Related

SQL: Finding values in sets, that only appear once

Using Oracle SQL, I need to find the IDs (ICFPROKEYI) that occur more then once, but have a certain field (ICFFLDC) only once:
ICFPROKEYI|ICFKAVKEYI|ICFNUMS|ICFFLDC
----------|----------|-------|-----------------------------
2234884| 5887| 0|Farbe.14870
2234884| 5887| 1|Ueberschrift_i_24291101.18563
2234884| 5888| 0|Farbe.14870
2234884| 5889| 0|Farbe.14870
2234884| 5890| 0|Farbe.14870
2234884| 5896| 0|Farbe.14870
In this case, 2234884, because it appears 6 times but has a value (Ueberschrift_i_24291101.18563) appear only once
You can try this:
select a.ICFPROKEYI from table a join table b
on a.ICFPROKEYI = b.ICFPROKEYI and a.ICFFLDC <> b.ICFFLDC
GROUP BY icfprokeyi and use HAVING count(*) > 1 to get the icfprokeyi that appear more than once and GROUP BY icfprokeyi, icffldc and use HAVING count(*) = 1 to get the icfprokeyi where the icffldc doesn't exist in another row with the same icfprokeyi. Then join both aggregations.
SELECT x1.icfprokeyi
FROM (SELECT t1.icfprokeyi
FROM elbat t1
GROUP BY t1.icfprokeyi
HAVING count(*) > 1) x1
INNER JOIN (SELECT t2.icfprokeyi
FROM elbat t2
GROUP BY t2.icfprokeyi,
t2.icffldc
HAVING count(*) = 1) x2
ON x2.icfprokeyi = x1.icfprokeyi;
Here is the postgres query:
select ICFPROKEYI,ICFFLDC from table group by ICFPROKEYI,ICFFLDC having count(*)=1;
Help yourself to write the oracle equivalent for it.
I've tried this with MySQL and might be applicable in oracle as well.
SELECT ICFPROKEYI
FROM <yourtable> WHERE ICFPROKEYI IN
(
SELECT ICFPROKEYI
FROM <yourtable>
GROUP BY ICFPROKEYI
HAVING COUNT(ICFPROKEYI) > 1
)
GROUP BY ICFPROKEYI, ICFFLDC
HAVING cnt(ICFFLDC) = 1
You can simply use GROUP BY with HAVING (two conditions) as following:
SELECT
ICFPROKEYI
FROM <yourtable>
GROUP BY ICFPROKEYI
HAVING COUNT(1) > 1
AND SUM(CASE WHEN ICFFLDC = 'Ueberschrift_i_24291101.18563'
THEN 1 END) = 1
-- Update
After #ankit specified that it can be any value(not fixed value - Ueberschrift_i_24291101.18563), OP can achieve the desired result using following query:
SELECT ICFPROKEYI
FROM
( SELECT T.ICFPROKEYI,
COUNT(1) OVER(
PARTITION BY T.ICFPROKEYI, ICFFLDC
) AS CNT
FROM YOURTABLE T
)
WHERE CNT = 1
Cheers!!
I have replicated this on my local, please find the below SQL block and try it yourself
drop table test;
CREATE TABLE test(
ICFPROKEYI INTEGER NOT NULL
,ICFKAVKEYI INTEGER NOT NULL
,ICFNUMS number(1,0) NOT NULL
,ICFFLDC VARCHAR(30) NOT NULL
);
INSERT INTO test(ICFPROKEYI,ICFKAVKEYI,ICFNUMS,ICFFLDC) VALUES (2234884,5887,0,'Farbe.14870');
INSERT INTO test(ICFPROKEYI,ICFKAVKEYI,ICFNUMS,ICFFLDC) VALUES (2234884,5887,1,'Ueberschrift_i_24291101.18563');
INSERT INTO test(ICFPROKEYI,ICFKAVKEYI,ICFNUMS,ICFFLDC) VALUES (2234884,5888,0,'Farbe.14870');
INSERT INTO test(ICFPROKEYI,ICFKAVKEYI,ICFNUMS,ICFFLDC) VALUES (2234884,5889,0,'Farbe.14870');
INSERT INTO test(ICFPROKEYI,ICFKAVKEYI,ICFNUMS,ICFFLDC) VALUES (2234884,5888,0,'Farbe.14870');
INSERT INTO test(ICFPROKEYI,ICFKAVKEYI,ICFNUMS,ICFFLDC) VALUES (2234884,5889,0,'Farbe.14870');
INSERT INTO test(ICFPROKEYI,ICFKAVKEYI,ICFNUMS,ICFFLDC) VALUES (2234885,5890,0,'Farbe.14870');
INSERT INTO test(ICFPROKEYI,ICFKAVKEYI,ICFNUMS,ICFFLDC) VALUES (2234885,5896,0,'Farbe.14870');
Query
SELECT A.ICFPROKEYI FROM (select ICFPROKEYI,ICFFLDC, count(*) AS ICFFLDC_CNT from test
group by ICFPROKEYI,ICFFLDC)A LEFT OUTER JOIN
(select ICFPROKEYI,count(*) as ICFPROKEYI_CNT from test group by ICFPROKEYI)B
ON A.ICFPROKEYI = B.ICFPROKEYI WHERE A.ICFFLDC_CNT = 1AND B.ICFPROKEYI_CNT > 1 ;

Possible to Search Partial Matched Strings from same table?

I have a table and lets say the table has items with the item numbers:
12345
12345_DDM
345653
2345664
45567
45567_DDM
I am having trouble creating a query that will get all of the _DDM and the corresponding item that has the same prefix digits.
So in this case I'd want both 12345 and 12345_DDM etc to be returned
Use like to find rows with _DDM.
Use EXISTS to find rows with numbers also having a _DDM row.
working demo
select *
from tablename t1
where columnname LIKE '%_DDM'
or exists (select 1 from tablename t2
where t1.columnname + '_DDM' = t2.columnname)
Try this query:
--sample data
;with tbl as (
select col from (values ('12345'),('12345_DDM'),('345653'),('2345664'), ('45567'),('45567_DDM')) A(col)
)
--select query
select col from (
select col,
prefix,
max(case when charindex('_DDM', col) > 0 then 1 else 0 end) over (partition by prefix) [prefixGroupWith_DDM]
from (
select col,
case when charindex('_DDM', col) - 1 > 0 then substring(col, 1, charindex('_DDM', col) - 1) else col end [prefix]
from tbl
) a
) a where [prefixGroupWith_DDM] = 1

Need to get the column from the table in exists clause

I have a query below:
SELECT AIDI.LOAN_NUM, AIDI.LOCATION_CODE, AIDI.ORD_NUM, AIDI.MTN, AIDI.LOAN_STATUS, COUNT(*)
FROM table1 AIDI
WHERE AIDI.LOAN_STATUS = 'A'
AND EXISTS (SELECT 1 FROM ORDERS AO
WHERE AO.ACE_ORD_NUM = AIDI.ORD_NUM
AND AO.ACE_ORD_COMPLETION_TIME >= TRUNC(SYSDATE -1)
AND AO.ACE_ORD_COMPLETION_TIME < TRUNC(SYSDATE))
GROUP BY AIDI.LOAN_NUM, AIDI.LOCATION_CODE, AIDI.ORD_NUM, AIDI.MTN, AIDI.LOAN_STATUS
HAVING COUNT(*) > 1;
I need to get the AO.ACE_ORD_COMPLETION_TIME this column into select clause so that i can see the date also in the result set.

Get data from table using group by

I have a Emptbl in which I have EmpType Column.
In EmpType I have following data for example :
E0123
M0123
E1245
E4578
M1245
E0478
M4789
E4762
Now I want to get only those emp data which have same EmpType for example below data:
E0123
M0123
E1245
M1245
And want to show this data as group by as 0123 and 1245
So how to get above data? I use UNION but it does not get valida data.
Thanks
Try this:
select substring(emptype, 2, len(emptype))
from emptbl
group by substring(emptype, 2, len(emptype))
having count(*) > 1
The hard-coded 2 is based on your sample data. If instead you had an arbitrary number of letters before the numeric part, e.g. 'ABCDEFG0123', you could use patindex to get the starting index for your substring like so;
select substring(emptype, patindex('%[0-9]%',emptype), len(emptype)
Select A.*
From EmpTbl A
Inner Join
EmpTbl B
On SubString(A.EmpType, 2, 4) = SubString(B.EmpType, 2, 4) And
SubString(A.EmpType, 1, 1) <> SubString(B.EmpType , 1, 1)
;with CTE as (Select Name,SUBSTRING(Name,2,5) as Number, ROW_NUMBER()
OVER (PARTITION By SUBSTRING(Name,2,5) ORDER BY Name) AS Row
from #Temp)
Select Temp.Name
From CTE C
Cross Apply (Select Name FRom CTE T Where T.Number=C.Number) as Temp
Where C.Row>1
Here is the fiddle sample
select top 4 id from
(
select id,rn=row_number()over(partition by right(id,3) order by right(id,3)) from #t
)x
SEE IT LIVE
This is the smallest query that works:
select substr(a.emptype, 2) num
join emptbl a
join emptbl b on substr(a.emptype, 2) = substr(b.emptype, 2)
and a.emptype != b.emptype

SQL: Modify query result rows that have a unique value

I have a sqlite query that returns something like the following with columns [letter, number]:
("a", 1)
("a", 2)
("b", 3)
("c", 3)
I want to retrieve the number column as 0 if the letter is distinct. How is it done?
Expected output:
("a", 1)
("a", 2)
("b", 0)
("c", 0)
SELECT tba.mychar
-- if tbu.mychar is null, then the letter is not unique
-- when it happens, the letter is not "unique" thus use the number column
-- else use zero for "unique" letters
, CASE WHEN tbu.mychar IS NULL THEN tba.mynum ELSE 0 END AS newnum
FROM mytab tba
LEFT JOIN (
-- this subquery only returns the letters that don't repeat
SELECT mychar
FROM mytab
GROUP BY mychar
HAVING COUNT(*) = 1
) AS tbu ON tba.mychar=tbu.mychar
You can use a sub-query:
select t1.col1,
case when t2.cnt > 1 then t1.col2 else 0 end col2
from table1 t1
left join
(
select count(*) as cnt, col1
from table1
group by col1
) t2
on t1.col1 = t2.col1
See SQL Fiddle with Demo
How about (SQL Fiddle):
SELECT Q.letter,
CASE WHEN (SELECT COUNT(*) FROM (query) QQ WHERE QQ.letter = Q.letter) = 1 THEN 0
ELSE Q.number
END AS number
FROM (query) Q
Note, replace "query" with the query that generates your first result.
It's possible to do this using a UNION ALL of 2 separate statements (one for repeated letters and one for letters that only occur once):
SELECT letter, number
FROM tableName
WHERE letter IN (
SELECT letter
FROM tableName
GROUP BY letter
HAVING COUNT(1) > 1
)
UNION ALL
SELECT letter, 0
FROM tableName
WHERE letter IN (
SELECT letter
FROM tableName
GROUP BY letter
HAVING COUNT(1) = 1
)