Selecting the lowest value of a character string in a grouped data - abap

I'm trying to create a SAP Query (SQ02).
My dataset is grouped based on a value of a field (example below).
I need to select and output the lowest value of another field, but its a mixed character - Letter + a number, I need the lowest number.
I have this piece of code right now, but it only brings back the value attached to the master account and the logic fails in the master account does not have the lowest value.
Select MIN( KLABC )
FROM KNVV
INTO CLS2
WHERE KUNNR IN
( SELECT KUNNR
FROM KNB1
WHERE EKVBD = KNB1-EKVBD ).
IF cls2+1(1) > KNVV-KLABC+1(1) AND KNVV-KLABC+0(1) = 'R'.
clear CLS2.
Select MIN( KLABC )
FROM KNVV
INTO CLS2
WHERE KLABC LIKE 'R%'
AND KUNNR IN
( SELECT KUNNR
FROM KNB1
WHERE EKVBD = KNB1-EKVBD ).
ENDIF.
Example dataset:
Customer Class Group
1001 R1 1001
301048 R2 1001
10015 A1 10015
306069 A2 10015
6042482 R1 10025
10027 R1 10027
303226 R2 10027
10028 A4 10028
306070 A4 10028
10034 A2 10034
303724 A5 10034
403558 A7 10034
5042 A1 10047
302673 A3 10047
The intermediate result would correspond to something like SELECT MIN( class ) AS Class2, group FROM abovetable GROUP BY group would give:
Class2 Group
R1 1001
A1 10015
R1 10025
R1 10027
A4 10028
A2 10034
A1 10047
By merging the intermediate result, the final result would look something like this:
Customer Class Group Class2
1001 R1 1001 R1
301048 R2 1001 R1
10015 A1 10015 A1
306069 A2 10015 A1
6042482 R1 10025 R1
10027 R1 10027 R1
303226 R2 10027 R1
10028 A4 10028 A4
306070 A4 10028 A4
10034 A2 10034 A2
303724 A5 10034 A2
403558 A7 10034 A2
5042 A1 10047 A1
302673 A3 10047 A1
Just the number would suffice too.

The following code will bring back the lowest valued entry in the group.
Select MIN( KLABC )
FROM KNVV
INTO CLS2
WHERE KLABC LIKE 'R%'
AND KUNNR IN
( SELECT KUNNR
FROM KNB1
WHERE EKVBD = KNB1-EKVBD
AND KUNNR IN
( SELECT KUNNR
FROM KNA1
WHERE LOEVM NE 'X' ) ).
IF CLS2 = ''.
Select MIN( KLABC )
FROM KNVV
INTO CLS2
WHERE KLABC LIKE 'A%'
AND KUNNR IN
( SELECT KUNNR
FROM KNB1
WHERE EKVBD = KNB1-EKVBD
AND KUNNR IN
( SELECT KUNNR
FROM KNA1
WHERE LOEVM NE 'X' ) ).
IF CLS2 = ''.
Select MIN( KLABC )
FROM KNVV
INTO CLS2
WHERE KUNNR IN
( SELECT KUNNR
FROM KNB1
WHERE EKVBD = KNB1-EKVBD
AND KUNNR IN
( SELECT KUNNR
FROM KNA1
WHERE LOEVM NE 'X' ) ).
ENDIF.
ENDIF.
As another requirement I also had to make the sure Customer class 1st letter matches with the result field, I've created an extra field with this code. It will match the original Class Letter and the value picked for the group by the above code.
CLEAR CLS1.
IF CLS2 NE ' '
AND KNVV-KLABC+0(1) = 'R' OR KNVV-KLABC+0(1) = 'A'.
CONCATENATE KNVV-KLABC+0(1) CLS2+1(1)
INTO CLS1.
ELSE.
CLS1 = CLS2.
ENDIF.

Related

order the results of one table based on it's availability in another table psql

I have 5 tables A, A1, A2, A3, A4.
A has the foreign key relationship with remaining 4 tables.
I want order A by first checking availability in A1 first then in A2 and so on.
So results should be displayed in order by it's availability in A1, A2, A3, A4.
select * from A as main
order by (select abc from A1 where main.abc = A1.abc), (select abc from A2 where main.abc = A2.abc), (select abc from A3 where main.abc = A3.abc), (select abc from A4 where main.abc = A4.abc)
if there are 10 records in A table then i want all 10 records in result but that records should be ordered by it's availability in A1, A2, A3 and A4
little help will be appreciated.
Use LEFT JOIN and COALESCE
select distinct A.*
from A
LEFT JOIN A1 ON A.abc = A1.abc
LEFT JOIN A2 ON A.abc = A2.abc
LEFT JOIN A3 ON A.abc = A3.abc
LEFT JOIN A4 ON A.abc = A4.abc
ORDER BY COALESCE(A1.abc,A2.abc,A3.abc,A4.abc)
However, it does not make much sense. The ordering will be according to the abc value. If you intend to order according to some value in A1 - A4, then use it instead of abc in COALESCE.
If you want rows being in A1 first then you might employ || to enforce ordering according to A1 - A4 existence (if the abc attribute is varchar)
select distinct A.*
from A
LEFT JOIN A1 ON A.abc = A1.abc
LEFT JOIN A2 ON A.abc = A2.abc
LEFT JOIN A3 ON A.abc = A3.abc
LEFT JOIN A4 ON A.abc = A4.abc
ORDER BY COALESCE('a' || A1.abc, 'b' || A2.abc, 'c' || A3.abc, 'd' || A4.abc)
You can sort on EXISTance:
-- sample data
CREATE TABLE a ( abc integer not null primary key);
INSERT INTO a(abc)
select generate_series(1,25);
CREATE TABLE a2 AS select * FROM a where abc %2 = 0;
CREATE TABLE a3 AS select * FROM a where abc %3 = 0;
CREATE TABLE a5 AS select * FROM a where abc %5 = 0;
CREATE TABLE a7 AS select * FROM a where abc %7 = 0;
ALTER TABLE a2 ADD primary key(abc);
ALTER TABLE a3 ADD primary key(abc);
ALTER TABLE a5 ADD primary key(abc);
ALTER TABLE a7 ADD primary key(abc);
-- Query
select * from a
ORDER BY exists (select * from a2 where abc=a.abc) desc
, exists (select * from a3 where abc=a.abc) desc
, exists (select * from a5 where abc=a.abc) desc
, exists (select * from a7 where abc=a.abc) desc
, a.abc -- tie-breaker
;
Result:
CREATE TABLE
INSERT 0 25
SELECT 12
SELECT 8
SELECT 5
SELECT 3
ALTER TABLE
ALTER TABLE
ALTER TABLE
ALTER TABLE
abc
-----
6
12
18
24
10
20
14
2
4
8
16
22
15
21
3
9
5
25
7
1
11
13
17
19
23
(25 rows)
Use COALESCE
SELECT A.*
FROM A LEFT JOIN A1 ON A.ID = A1.ID
LEFT JOIN A2 ON A.ID = A2.ID
LEFT JOIN A3 ON A.ID = A3.ID
LEFT JOIN A4 ON A.ID = A4.ID
ORDER BY COALESCE(A1.ID ,A2.ID ,A3.ID ,A4.ID )

Oracle SQL -- how to delete partial duplicates with a preference

Could you please help me in deleting duplicates (partial) from table? I have a table containing 5 columns. And in this table I have duplicates -- but only 4 columns are the same and one of the columns (field5) is different. That is:
F1 F2 F3 F4 F5
A1 A2 A3 A4 103
A1 A2 A3 A4 3
So, for a duplicate, 4 columns/fields are the same, except the 5th one. And I want to delete the row containing number "103", that's, a higher number. How can I achieve this?
If this was a normal duplicate, I would just use max(rowid) and remove that row. But now this could delete the row containing lower number instead of the higher number.
One method that I can think of is creating a new table containing rows which are duplicate and Field5 has a higher number from this table. Then deleting rows from original table by comparing it to this new table. But that seems not so good solution to me -- especially if the original table is big, this might take long time.
Any help would be much appreciated. Thank you.
Idea is to keep a record for each combinations of F1,F2,F3,F4 and delete the rest.
Try this:
DELETE FROM TABLE_NAME WHERE ROWID IN
(SELECT ROWID FROM
(SELECT ROWID, row_number() OVER(PARTITION BY F1,F2,F3,F4 ORDER BY F5) RN
FROM TABLE_NAME)
WHERE RN<>1);
How about this?
SQL> select * from test order by f1, f5;
F1 F2 F3 F4 F5
-- -- -- -- ----------
a1 a2 a3 a4 3
a1 a2 a3 a4 50 --> delete
a1 a2 a3 a4 103 --> delete
b1 b2 b3 b4 2
b1 b2 b3 b4 200 --> delete
c1 c2 c3 c4 1
6 rows selected.
SQL> delete from test t
2 where rowid not in (select rowid
3 from test t1
4 where t1.f1 = t.f1
5 and t1.f2 = t.f2
6 and t1.f3 = t.f3
7 and t1.f4 = t.f4
8 and t1.f5 =
9 (select min (t2.f5)
10 from test t2
11 where t2.f1 = t.f1
12 and t2.f2 = t.f2
13 and t2.f3 = t.f3
14 and t2.f4 = t.f4));
3 rows deleted.
SQL> select * from test order by f1, f5;
F1 F2 F3 F4 F5
-- -- -- -- ----------
a1 a2 a3 a4 3
b1 b2 b3 b4 2
c1 c2 c3 c4 1
SQL>
I normally just do this:
delete demo
where rowid in
( select lead(rowid) over (partition by f1, f2, f3, f4 order by f5) as next_rowid
from demo );
That is, delete every "next" row in order of f5 within its (f1, f2, f3, f4) group.

Parent/ child hierarchy - SQL Server (tree)

I am trying to get the structure of parent/ child via sql query.
I have this code:
state_code, description
A000
A010
B000
B010
B01A
B01B
B020
B02A
I want a structure like parent_id, element_id and desc
Such that:
A
A000
-01 (from A)
--A010
B
B000
-01
--B010
--B01A
-02
--
I tried it using this code, but unfortunately it doesn't work.
select distinct
SUBSTRING(REPLACE(state_cd,'0',''),1, LEN(REPLACE(state_cd, '0', '')) -1) AS parent_id, REPLACE(state_cd,'0','') state_id,
state_cd,
desc_1
from
CATEGORYSTRUCTURE
inner join
CATEGORYITEMS on CATEGORYSTRUCTURE.struct_id = CATEGORYITEMS.struct_id
left join
STATECODES on key_1 = state_cd
where
state_type = '22'
UNION ALL
select distinct
SUBSTRING(REPLACE(state_cd,'0',''),1, LEN(REPLACE(state_cd, '0', '')) -1) AS parent_id,
REPLACE(state_cd,'0','') state_id,
stat_cd,
desc_1
from
CATEGORYITEMS
inner join
STATECODES on key_1 = state_cd
where
state_type = '22'
My result:
parent_id stat_id stat_cd desc_1
O O000 11
P P000 Pa)
Q Q000 prod
R R000 Zus
S S000 Ver
T T000 Pack
A A1 A010 Get
A A1 A100 Kakt
A A3 A030 Kol
A A7 A070 Milk
A A8 A080 Spt
A1 A11 A110 Lo
A1 A1A A01A Hcht
What I want is everything under respective characters
A A7 A070 Milk
A A8 A080 Spt
A A11 A110 Lo
A1 A1A A01A Hcht
I can't understand what exactly you want, But I think this query can help you:
SELECT state_cd
, SUBSTRING(state_cd,1,1) As Parent0
, CASE WHEN state_cd Like '__[^0]_' THEN SUBSTRING(state_cd,2,2) ELSE '' END As Parent1
, CASE WHEN state_cd Like '___[^0]' THEN SUBSTRING(state_cd,4,1) ELSE '' END As Parent2
FROM yourTable

need to re-arrange data of sql table

I have following primary table.
ID Email TM UR EA1 TM1 UR1 TM2 UR2 TM3 UR3
1 abc#b.com a1 b1 a#a.com a2 b2 a3 b3 a4 b4
And need output as follows.
ID Email TM UR
1 abc#b.com a1 b1
1 a#a.com a2 b2
1 a3 b3
1 a4 b4
Edit: I have already solved this by using UNION. I need optimize way to do that as I have many such columns for one record, and Union is not the solution that I'm looking for.
SELECT ID, Email, TM, UR
FROM TABLE
UNION
SELECT ID, EA1 Email, TM1 TM, UR1 UR
FROM TABLE
UNION
SELECT ID, '' Email, TM2 TM, UR2 UR
FROM TABLE
UNION
SELECT ID, '' Email, TM3 TM, UR3 UR
FROM TABLE

PostgreSQL cross join Table

Initial Situation:
Table1:
Table1 s1_a s2_b s3_c s_key
Table1 a1 b1 c1 1
Table1 a2 b2 c2 2
Table1 a3 b3 c3 3
Table1 a4 b4 c4 4
Table2:
Table2 d1_q d2_w d3_e d_key
Table2 q1 w1 e1 1
Table2 q2 w2 e2 2
Table2 q3 w3 e3 3
How can I get this result: common columns are s_key & d_key -> key
Extract View s1_a s2_b s3_c key d1_q d2_w d3_e
Extract View a1 b1 c1 1
Extract View a2 b2 c2 2
Extract View a3 b3 c3 3
Extract View a4 b4 c4 4
Extract View 1 q1 w1 e1
Extract View 2 q2 w2 e2
Extract View 3 q3 w3 e3
No reason for a cross join here. Just an old fashioned UNION ALL will do the trick:
SELECT s1_a, s2_b, s3_c, s_key, NULL as d1_q, NULL as d2_w, NULL as d3_e FROM Table1
UNION ALL
SELECT NULL, NULL, NULL, d_key, d1_q, d2_w, d3_e FROM Table2