Group by using Analytical function Oracle - sql

I have the below demo code.
How can I get the desired output.Its just not coming in my mind :-(.It has to be a simple change.
WITH Abc AS (SELECT 'AB' AS code,'Z12' AS des, 123 AS tk FROM dual UNION
SELECT 'AB','Z14',234 FROM dual UNION
SELECT 'ACB','D12',34 FROM dual UNION
SELECT 'ACB','D12',36 FROM dual UNION
SELECT 'ACB','F12',35 FROM dual UNION
SELECT 'ABX','G44',243 FROM dual UNION
SELECT 'ABX','H44',654 FROM dual UNION
SELECT 'ABX','J12',534 FROM dual UNION
SELECT 'ABQ',NULL,356 FROM dual)
SELECT DISTINCT tk,code,des ,code||'_'||row_number () OVER (PARTITION BY code ORDER BY code,des ) AS str FROM abc
ORDER BY 2,3;
OUTPUT :
tk code des str
--- --- --- ---
123 AB Z12 AB_1
234 AB Z14 AB_2
356 ABQ ABQ_1
243 ABX G44 ABX_1
654 ABX H44 ABX_2
534 ABX J12 ABX_3
34 ACB D12 ACB_1 --- ACB_1
36 ACB D12 ACB_2 ----I want ACB_1 here too since desc is same for that code
35 ACB F12 ACB_3

**USE RANK() instead of rownumber()**
WITH Abc AS (SELECT 'AB' AS code,'Z12' AS des, 123 AS tk FROM dual UNION
SELECT 'AB','Z14',234 FROM dual UNION
SELECT 'ACB','D12',34 FROM dual UNION
SELECT 'ACB','D12',36 FROM dual UNION
SELECT 'ACB','F12',35 FROM dual UNION
SELECT 'ABX','G44',243 FROM dual UNION
SELECT 'ABX','H44',654 FROM dual UNION
SELECT 'ABX','J12',534 FROM dual UNION
SELECT 'ABQ',NULL,356 FROM DUAL)
SELECT DISTINCT TK,CODE,DES ,CODE||'_'||rank() OVER (PARTITION BY CODE ORDER BY CODE,DES ) AS STR FROM ABC
ORDER BY 2,3;

Related

Oracle filter groups that contains more than one row condition

I need a SQL query for Oracle that select groups that contains the elements "ABC" and "ANQ"
group X Column Q
-------- ---------
123 ABC
123 AAA
123 ANQ
456 ANQ
456 PKR
579 AAA
579 XYZ
886 ABC
The desired result should be
group X Column Q
-------- ---------
123 ABC
123 AAA
123 ANQ
You can query the table only once by using the analytic COUNT function with conditional aggregation:
SELECT x,
q
FROM (
SELECT x,
q,
COUNT(CASE q WHEN 'ABC' THEN 1 END) OVER (PARTITION BY x) AS num_abc,
COUNT(CASE q WHEN 'ANQ' THEN 1 END) OVER (PARTITION BY x) AS num_anq
FROM table_name
)
WHERE num_abc > 0
AND num_anq > 0;
Which, for the sample data:
CREATE TABLE table_name (X, Q) AS
SELECT 123, 'ABC' FROM DUAL UNION ALL
SELECT 123, 'AAA' FROM DUAL UNION ALL
SELECT 123, 'ANQ' FROM DUAL UNION ALL
SELECT 456, 'ANQ' FROM DUAL UNION ALL
SELECT 456, 'PKR' FROM DUAL UNION ALL
SELECT 579, 'AAA' FROM DUAL UNION ALL
SELECT 579, 'XYZ' FROM DUAL UNION ALL
SELECT 886, 'ABC' FROM DUAL;
Outputs:
X
Q
123
ABC
123
AAA
123
ANQ
fiddle
For example:
Sample data:
SQL> with test (x, q) as
2 (select 123, 'abc' from dual union all
3 select 123, 'aaa' from dual union all
4 select 123, 'anq' from dual union all
5 select 456, 'anq' from dual union all
6 select 456, 'pkr' from dual union all
7 select 579, 'aaa' from dual union all
8 select 579, 'xyz' from dual union all
9 select 886, 'abc' from dual
10 )
Query:
11 select x, q
12 from test a
13 where exists (select null
14 from test b
15 where b.q in ('abc', 'anq')
16 and b.x = a.x
17 group by b.x
18 having count(distinct b.q) = 2
19 );
X Q
---------- ---
123 abc
123 aaa
123 anq
SQL>

Generate Result based on max count in secondary column after a join

I have two tables which have a common key between them, and quite a lot of other important infos ; for the sake of simplicity i will be using Combination A and Combination B. When a combination is met, whichever table has the maximum number of records should be the source where i collect the information ; in this case say IDs. The priority when counts are same is Table1.
COMMONKEY column is the combination/join condition in my tables.
(Table 1)
SELECT '123' table1_id,'Comb A' commonkey from dual UNION
SELECT '124' table1_id,'Comb A' commonkey from dual UNION
SELECT '125' table1_id,'Comb A' commonkey from dual UNION
SELECT '126' table1_id,'Comb A' commonkey from dual UNION
SELECT '215' table1_id,'Comb B' commonkey from dual UNION
SELECT '216' table1_id,'Comb B' commonkey from dual UNION
SELECT '559' table1_id,'Random Combination 1' commonkey from dual UNION
SELECT '560' table1_id,'Random Combination 2' commonkey from dual ;
( Table 2 )
SELECT 'abc1' table2_id,'Comb A' commonkey from dual UNION
SELECT 'abc2' table2_id,'Comb A' commonkey from dual UNION
SELECT 'abc3' table2_id,'Comb A' commonkey from dual UNION
SELECT 'abc4' table2_id,'Comb A' commonkey from dual UNION
SELECT 'xyz1' table2_id,'Comb B' commonkey from dual UNION
SELECT 'xyz2' table2_id,'Comb B' commonkey from dual UNION
SELECT 'xyz3' table2_id,'Comb B' commonkey from dual UNION
SELECT 'xyz2' table2_id,'Comb B' commonkey from dual UNION
SELECT '416abc1' table2_id,'Random Combination 91' commonkey from dual UNION
SELECT '416abc2' table2_id,'Random Combination 92' commonkey from dual;
Result Set Expected :
ID COMMONKEY
123 Comb A
124 Comb A
125 Comb A
126 Comb A
xyz1 Comb B
xyz2 Comb B
xyz3 Comb B
559 Random Combination 1
560 Random Combination 1
416abc1 Random Combination 91
416abc2 Random Combination 92
Updated Image :
( the image shows a screenshot of the trail data in an excel; The Requirement and Strategy are color mapped to make it quickly understandable )
I need to generate the result set using SQL as follows :
When table1.commonkey = table2.commonkey hits, I need to-
If table1 has 10 IDs, table2 has 5 IDs -> Pick 10 IDs from table1.
If table1 has 15 IDs, table2 has 30 IDs -> Pick 30 IDs from table2.
If table1 has 4 IDs, table2 has 4 IDs -> Pick 4 IDs from table1.
( when equal, choose table1 IDs )
When no matches occur with the common key, prevent a cross join and add in the rowsets linearly to the result table.
Edit : I've initially gone on routes with
a left join b where b.key IS null ;
a full outer join b where b.key IS NULL or a.key is NULL ;
to achieve workarounds with A-B or B-A result sets but both these approaches were quite wrong. Gathering Delta sets or Exclusion sets didnt go well.
Here's one option; see comments within code
SQL> with
2 -- sample data
3 a (id, ckey) as
4 (select '123', 'ca' from dual union all
5 select '124', 'ca' from dual union all
6 select '125', 'ca' from dual union all
7 select '126', 'ca' from dual union all
8 select '215', 'cb' from dual union all
9 select '216', 'cb' from dual union all
10 select '551', 'r1' from dual union all
11 select '552', 'r2' from dual
12 ),
13 b (id, ckey) as
14 (select 'abc1', 'ca' from dual union all
15 select 'abc2', 'ca' from dual union all
16 select 'abc3', 'ca' from dual union all
17 select 'abc4', 'ca' from dual union all
18 select 'xyz1', 'cb' from dual union all
19 select 'xyz2', 'cb' from dual union all
20 select 'xyz3', 'cb' from dual union all
21 select '9991', 'r3' from dual union all
22 select '9992', 'r4' from dual
23 ),
24 -- count rows per each CKEY (common key)
25 tempa as
26 (select id, ckey, count(*) over (partition by ckey) cnt
27 from a
28 ),
29 tempb as
30 (select id, ckey, count(*) over (partition by ckey) cnt
31 from b
32 )
33 -- final query
34 select distinct
35 case when a.cnt >= b.cnt then a.id
36 else b.id
37 end id,
38 a.ckey
39 from tempa a join tempb b on b.ckey = a.ckey
40 union all
41 select ckey, id from a
42 where not exists (select null from b where a.ckey = b.ckey)
43 union all
44 select ckey, id from b
45 where not exists (select null from a where a.ckey = b.ckey)
46 order by 1, 2;
which results in
ID CKEY
---- -----
r1 551
r2 552
r3 9991
r4 9992
xyz1 cb
xyz2 cb
xyz3 cb
123 ca
124 ca
125 ca
126 ca
11 rows selected.
SQL>

how can to_char with zero before number in oracle

I have database like below:
WITH TB AS(
SELECT 1 NONB FROM DUAL UNION ALL
SELECT 89 NONB FROM DUAL UNION ALL
SELECT 193 NONB FROM DUAL
)
SELECT * FROM TB
I want change column NONB to_char(NONB) and display zero before the number like below.
001
089
189
How can I do this? Thanks.
Use lpad():
select lpad(nonb, 3, '0')
from tb;
Here is a rextester.
Use this:
WITH TB AS(
SELECT 1 NONB FROM DUAL UNION ALL
SELECT 89 NONB FROM DUAL UNION ALL
SELECT 193 NONB FROM DUAL
)
SELECT to_char(nonb, 'FM000') FROM TB

Optimize Group by Hour Query

Please help to optimize my query. It looks too bulky.
I guess there is a better way to work with hours (datetime) in sql
There is a table dauditnew that is populated and population datetime is stored inside auditdate column.
Query returns rows count by hour.
SELECT t.Hour, COUNT(t.Hour) as Count FROM dauditnew d,
(SELECT 0 as Hour FROM DUAL UNION
SELECT 1 FROM DUAL UNION
SELECT 2 FROM DUAL UNION
SELECT 3 FROM DUAL UNION
SELECT 4 FROM DUAL UNION
SELECT 5 FROM DUAL UNION
SELECT 6 FROM DUAL UNION
SELECT 7 FROM DUAL UNION
SELECT 8 FROM DUAL UNION
SELECT 9 FROM DUAL UNION
SELECT 10 FROM DUAL UNION
SELECT 11 FROM DUAL UNION
SELECT 12 FROM DUAL UNION
SELECT 13 FROM DUAL UNION
SELECT 14 FROM DUAL UNION
SELECT 15 FROM DUAL UNION
SELECT 16 FROM DUAL UNION
SELECT 17 FROM DUAL UNION
SELECT 18 FROM DUAL UNION
SELECT 19 FROM DUAL UNION
SELECT 20 FROM DUAL UNION
SELECT 21 FROM DUAL UNION
SELECT 22 FROM DUAL UNION
SELECT 23 FROM DUAL) t
where
d.auditdate >= TO_DATE('25.04.2017 ' || t.Hour, 'dd.mm.yyyy HH24') and
d.auditdate <= TO_DATE('25.04.2017 ' || t.Hour || '_59_59', 'dd.mm.yyyy HH24_MI_SS')
group by t.Hour
You want to start with something like this:
select trunc(d.auditdate, 'HH24') as hh, count(*)
from dauditnew d
where d.auditdate >= '2017-04-25' and d.auditdate < '2017-04-26'
group by trunc(d.auditdate, 'HH24')
order by hh;
If this misses hours, then you can use a left join with this as a subquery.

How to insert multimple records of numbers with one statement in ORACLE and Sql-server using the same sentence

In my C++ program I tried something like this:
INSERT INTO TEMP_TABELA (OSE_ID) values (7,12,16,17,19,21,24,26,30,33,35,38,42,46,53,58,59,72,73,74,77,78,82,86,87,88,89,91,92,93,100,101,102,104,106,109,113,115,127,133,139,140,142,143,144,148,149,150,151,153,155,160,164,166,167,170,172,178,188,189,191,192,198,199,200,201,202,203,205,207,208,219,220,223,225,231,233,236,240,241,242,244,245,253);
But all I got was:
Description: There are fewer columns in the INSERT statement than values specified in the VALUES clause. The number of values in the VALUES clause must match the number of columns specified in the INSERT statement.
Source: Microsoft OLE DB Provider for SQL Server
The same sentence must work also on Oracle, because my program works for both.
Can anyone help me?
Oracle's and SQL Server's bulk insertion syntax is different from one another, so the safest means is to use individual INSERT statements:
INSERT INTO TEMP_TABELA (OSE_ID) values (7);
INSERT INTO TEMP_TABELA (OSE_ID) values (12);
INSERT INTO TEMP_TABELA (OSE_ID) values (16);
INSERT INTO TEMP_TABELA (OSE_ID) values (17);
...
INSERT INTO TEMP_TABELA (OSE_ID) values (253);
This works in Oracle, it split's on the string (assuming 10g+)
CREATE TABLE TESTX(NUM NUMBER);
INSERT INTO TESTX(NUM)
select regexp_substr (x, '[^,]+', 1, level) as token
from (SELECT '7,12,16,17,19,21,24,26,30,33,35,38,42,46,53,58,59,72,73,74,77,78,82,86,87,88,89,91,92,93,100,101,102,104,106,109,113,115,127,133,139,140,142,143,144,148,149,150,151,153,155,160,164,166,167,170,172,178,188,189,191,192,198,199,200,201,202,203,205,207,208,219,220,223,225,231,233,236,240,241,242,244,245,253' X FROM DUAL) t
connect by regexp_instr (x, '[^,]+', 1, level) > 0
84 rows inserted
Do this for Oracle:
INSERT INTO TEMP_TABELA (OSE_ID)
select 7 from dual union all
select 12 from dual union all
select 16 from dual union all
select 17 from dual union all
select 19 from dual union all
select 21 from dual union all
select 24 from dual union all
select 26 from dual union all
select 30 from dual union all
select 33 from dual union all
select 35 from dual union all
select 38 from dual union all
select 42 from dual union all
select 46 from dual union all
select 53 from dual union all
select 58 from dual union all
select 59 from dual union all
select 72 from dual union all
select 73 from dual union all
select 74 from dual union all
select 77 from dual union all
select 78 from dual union all
select 82 from dual union all
select 86 from dual union all
select 87 from dual union all
select 88 from dual union all
select 89 from dual union all
select 91 from dual union all
select 92 from dual union all
select 93 from dual union all
select 100 from dual union all
select 101 from dual union all
select 102 from dual union all
select 104 from dual union all
select 106 from dual union all
select 109 from dual union all
select 113 from dual union all
select 115 from dual union all
select 127 from dual union all
select 133 from dual union all
select 139 from dual union all
select 140 from dual union all
select 142 from dual union all
select 143 from dual union all
select 144 from dual union all
select 148 from dual union all
select 149 from dual union all
select 150 from dual union all
select 151 from dual union all
select 153 from dual union all
select 155 from dual union all
select 160 from dual union all
select 164 from dual union all
select 166 from dual union all
select 167 from dual union all
select 170 from dual union all
select 172 from dual union all
select 178 from dual union all
select 188 from dual union all
select 189 from dual union all
select 191 from dual union all
select 192 from dual union all
select 198 from dual union all
select 199 from dual union all
select 200 from dual union all
select 201 from dual union all
select 202 from dual union all
select 203 from dual union all
select 205 from dual union all
select 207 from dual union all
select 208 from dual union all
select 219 from dual union all
select 220 from dual union all
select 223 from dual union all
select 225 from dual union all
select 231 from dual union all
select 233 from dual union all
select 236 from dual union all
select 240 from dual union all
select 241 from dual union all
select 242 from dual union all
select 244 from dual union all
select 245 from dual union all
select 253 from dual
And this for SQL Server:
INSERT INTO TEMP_TABELA (OSE_ID)
select 7 union all
select 12 union all
select 16 union all
select 17 union all
select 19 union all
select 21 union all
select 24 union all
select 26 union all
select 30 union all
select 33 union all
select 35 union all
select 38 union all
select 42 union all
select 46 union all
select 53 union all
select 58 union all
select 59 union all
select 72 union all
select 73 union all
select 74 union all
select 77 union all
select 78 union all
select 82 union all
select 86 union all
select 87 union all
select 88 union all
select 89 union all
select 91 union all
select 92 union all
select 93 union all
select 100 union all
select 101 union all
select 102 union all
select 104 union all
select 106 union all
select 109 union all
select 113 union all
select 115 union all
select 127 union all
select 133 union all
select 139 union all
select 140 union all
select 142 union all
select 143 union all
select 144 union all
select 148 union all
select 149 union all
select 150 union all
select 151 union all
select 153 union all
select 155 union all
select 160 union all
select 164 union all
select 166 union all
select 167 union all
select 170 union all
select 172 union all
select 178 union all
select 188 union all
select 189 union all
select 191 union all
select 192 union all
select 198 union all
select 199 union all
select 200 union all
select 201 union all
select 202 union all
select 203 union all
select 205 union all
select 207 union all
select 208 union all
select 219 union all
select 220 union all
select 223 union all
select 225 union all
select 231 union all
select 233 union all
select 236 union all
select 240 union all
select 241 union all
select 242 union all
select 244 union all
select 245 union all
select 253
The parentheses in your statement in the example indicate to SQL Server that you want all that to be on one row. You need to enclose each row in parentheses and separate those by commas, i.e:
INSERT INTO TEMP_TABELA (OSE_ID)
values (7),
(12),
(16),
(17),
(19),
(21),
(24),...
I'm not sure if this will work in Oracle or not, but if not you may need to create a condition in your calling application to determine which DB it's working with and modify the query appropriately.
Similar to #OMGPonies can also do something like:
INSERT INTO TEMP_TABLEA(OSE_ID)
SELECT 7 union all
SELECT 12 ...
Not sure which is faster or even if you care about speed given the number of items you're inserting.
Not tested on oracle but I'm about 90% sure it will work.