Oracle Sql; Find same combination of columnvalues in two or more rows - sql

I need some help with my query. Been searching for ages but can`t come up with the right sql statement.
This my table DRAFT DFT (only 1 table, these are all the columns)
RowID|SID Number|Column C|RELS Number|Column E|Dr Number |Column G |
1------ | 23101----- |21-8-2014| 22234 ----- | UNR---------| 14243-----|2
2------ | 23101 ----- |22-8-2014| 22234 ----- | UNS---------| 14243 ---| 2
3------ | 23101------ |28-8-2014| 22232 ----- | FRE ---------| 14243 ---| 2
What I need is the following :
I need to select all the rows & Columns values of the table where the combination of the value in column SID Number and RELS Number are duplicate so what I must see is ony the following 2 rows:
1------ | 23101----- |21-8-2014| 22234 ----- | UNR---------| 14243-----|2
2------ | 23101 ----- |22-8-2014| 22234 ----- | UNS---------| 14243 ---| 2
AND NOT THIS:
1------ | 23101----- |21-8-2014| 22234 ----- | UNR---------| 14243-----|2
2------ | 23101 ----- |22-8-2014| 22234 ----- | UNS---------| 14243 ---| 2
**3------ | 23101------ |28-8-2014| 22232 ----- | FRE ---------| 14243 ---| 2**
because the combination of SID Number and RELS Number is not duplicate.
I know that the column value of Dr Number is the same in all 3 rows.
Does that matter for my sql statement?
This was my statement:
SELECT *
FROM DRAFT DFT
INNER JOIN (SELECT SID Number,RELS Number, COUNT(*) AS "TOTALCOUNT
FROM DRAFT DTF1GROUP BY SID Number,RELS Number
HAVING COUNT (*)>1
) B ON DTF.SID Number=B.SID Number AND DTF.RELS Number=B.RELS Number

Just use analytic functions:
select d.*
from (select d.*, count(*) over (partition by sid, rels) as cnt
from draft
) d
where cnt > 1;

Related

Select one row per JSON element in SQL field / convert JSON field into rows

I have a table with lots of rows like:
ID | Attributes
1 | {"Rank":1, "LoadLocation": London, "Driver":Tom}
2 | {"Rank":2, "LoadLocation": Southampton, "Driver":Dick}
3 | {"Rank":3, "DischargeLocation": Stratford}
There isn't a template for the JSON - it's a dumping ground for any number of attributes of the ID rows.
For use in a join I'd like to get these into a table this:
ID | Attribute Name | Attribute Value
1 | 'Rank' | 1
1 | 'LoadLocation' | 'London'
1 | 'Driver' | 'Tom'
2 | 'Rank' | 2
2 | 'LoadLocation' | 'Southampton'
2 | 'Driver' | 'Dick'
3 | 'Rank' | 3
3 | 'DischargeLocation'| 'Stratford'
I can see that I probably need to be using OpenJSON, but also that for that I likely need to know the explicit structure. I don't know the structure, even to the point of each row having a different numbe of attributes.
Any help gratefully received!
If you have sql-server-2016 and above, you can use OPENJSON with CROSS APPLY
DECLARE #TestData TABLE (ID INT, Attributes VARCHAR(500))
INSERT INTO #TestData VALUES
(1 ,'{"Rank":1, "LoadLocation": "London", "Driver":"Tom"}'),
(2 ,'{"Rank":2, "LoadLocation": "Southampton", "Driver":"Dick"}'),
(3 ,'{"Rank":3, "DischargeLocation": "Stratford"}')
SELECT T.ID, X.[key] AS [Attribute Name], X.value AS [Attribute Value]
FROM #TestData T
CROSS APPLY (SELECT * FROM OPENJSON(T.Attributes)) AS X
Result:
ID Attribute Name Attribute Value
----------- -------------------- -------------------
1 Rank 1
1 LoadLocation London
1 Driver Tom
2 Rank 2
2 LoadLocation Southampton
2 Driver Dick
3 Rank 3
3 DischargeLocation Stratford

Retrieve field offset via recursive query in db2

Assume that I've got key-value table of field_name-field_len pair.
As follows:
-----------------------------------
field_name | field_len |
-----------------------------------
FIELD_A | 10 |
-----------------------------------
FIELD_B | 20 |
-----------------------------------
...
-----------------------------------
FIELD_X | 2 |
-----------------------------------
FIELD_Y | 100 |
-----------------------------------
Then I need an offset of each field to be in third column.
Like this:
-----------------------------------------------------
field_name | field_len | offset |
-----------------------------------------------------
FIELD_A | 10 | 0 |
-----------------------------------------------------
FIELD_B | 20 | 10 |
-----------------------------------------------------
...
-----------------------------------------------------
FIELD_X | 2 | 250 |
-----------------------------------------------------
FIELD_Y | 100 | 252 |
-----------------------------------------------------
So I've wrote this script based on some manuals (1,2):
with offsets (column_name, length, offset) as
((select column_name, length, CAST(0 AS SMALLINT)
from myschema.sizes a
start with rrn(a) = 1)
union all
(select b.column_name, b.length, offset + o.length
from offsets o, myschema.sizes b
where rrn(b) between 2 and 100))
select * from offsets;
However, it keeps getting into infinite loop.
Also this version gives same result:
with offsets (column_name, length, offset) as
((select column_name, length, CAST(0 AS SMALLINT)
from myschema.sizes a
fetch first row only)
union all
(select b.column_name, b.length, offset + o.length
from offsets o join myschema.sizes b on b.column_name = o.column_name
where o.column_name <>'LAST_FIELD'))
select * from offsets;
I guess, that messed somewhere with exit condition, but can not figure exact place to fix it.
Would be great to avoid any table specific metadata like row count too.
You don't need a recursive CTE for this. Just a cumulative sum. Something like this:
select s.*,
(sum(field_len) over (order by rrn(s)) - field_len) as offset
from myschema.sizes s;
I'm not sure how the ordering is defined. It seems to be based on a function rrn().

How to count rows using group by

I have a table like this.
---------
| block |
---------
| A1 |
| A1 |
| A2 |
| A3 |
---------
I want to count found rows using group by, so it would return value like this.
--------------
| total_block|
--------------
| 3 |
--------------
What is the correct query to show results like that? I have already tried using SQL_CALC_FOUND_ROWS but it return values = A1, A2, A3. Thank you.
Looks like you just want the number of different blocks:
select count(distinct block) as total_block from tablename
Not the very nice approach , but if it has to be done via group by then, you can try this.
select count(cnt) from (select count(1) as cnt from table_inner group by block) table_outer;

Grouping by two values in same table

I have a table on the format
Ship_type | userid | Message
Neither of these columns are unique.
I want to count how many (unique) user id's that belong to each ship type, and thus find out which ship type is the most popular.
Example:
Ship_type | userid| Message
-------------- ------- ----------
Sailboat | 34241 | hello
Sailboat | 34241 | hi
Sailboat | 34241 | I'm on a boat!
Fishingvessel | 31245 | yo
Fishingvessel | 98435 | hi there
Here we see that there are two different fishingvessels and one sailboat.
If I do the following query:
select ship_type, count(ship_type) FROM db1.MessageType5 GROUP BY ship_type ORDER BY count(ship_type) ASC;
I get
Sailboat | 3
Fishingvessel | 2
which is wrong - as it counts the number of messages belonging to each ship_type.
Desired result:
Fishingvessel | 2
Sailboat | 1
You have to COUNT DISTINCT user ids (and ORDER BY ... DESC if you want the provided result):
SELECT ship_type, COUNT(DISTINCT userid) as cnt
FROM db1.MessageType5
GROUP BY ship_type
ORDER BY cnt DESC
See this fiddle.

SQL query to remove duplicates based on the modified date

I have a database table with the following columns regularization_dt, modified_dt and account_id. For a particular whenever an account is updated an entry is added in to the table with new modified_dt for the regularization_dt and account_id.
I want an SQL query to remove duplicates of regularization. Only one entry for the regularization should be selected based on the recent modified_dt.
For example the entries in the table are as follows:
regularization_dt | account_id | modified_dt
----------------- | ---------- | ----------
03-28-2013 | 123 |05-26-2014
03-28-2013 | 123 |01-14-2014
05-26-2014 | 123 |05-25-2014
The resulting query should yield:
regularization_dt | account_id | modified_dt
----------------- | ---------- | ----------
03-28-2013 | 123 |05-26-2014
05-26-2014 | 123 |05-25-2014
How should I remove duplicates of a column based on a different column?
select * from history where account_id = 123;
Sounds like you want to use an aggregate function and a GROUP BY :
SELECT regularization_dt,
account_id,
MAX(modified_dt) as modified_dt
FROM yourtable
GROUP BY regularization_dt,
account_id;
This should return deduplicated rows with only the latest modified_dt for rows with identical regularization_dt and account_id column values.