SQL search for minimum values related to a table of duplicates - sql

I have a SQL View that pumps out the following table, two columns
Column 1 Column 2
ID Value
1 10
1 12
1 15
2 3
2 6
I'd like to search for where record 1 returns it's minimum value (10) and record 2 returns it's minimum value (3)
Any help greatly appreciated.

SELECT
id
, MIN(value)
FROM yourview
GROUP BY id

You could try something like:
select [id], min([value]), max([value])
from viewname
group by id
order by id
The square brackets are SQL Server syntax to sidestep keywords; your database syntax may differ. What database are you using?

You could use Row_Number() OVER ().
; WITH cte AS (
SELECT id1 = 1, value = 10 UNION ALL
SELECT id1 = 1, value = 12 UNION ALL
SELECT id1 = 1, value = 15 UNION ALL
SELECT id1 = 2, value = 3 UNION ALL
SELECT id1 = 2, value = 6
)
SELECT z.id1, z.value
FROM (
SELECT id1, value, ROW_NUMBER() OVER ( PARTITION BY id1 ORDER BY value ASC ) AS rn
FROM cte
) z
WHERE z.rn = 1
Returns:
id1 value
1 10
2 3

Related

case statement after where clause to omit the row of data if satisfied

Hi I have a table as below and I'm trying to extract the data from them if and only if the below condition is satisfied.
ID Rank
45689 1
54789 2
98765 1
96541 2
98523 3
92147 4
96741 2
99999 10
If the ID starts with 4 and 9 or 5 and 9 and have same Rank then omit them. If ID starts with 9 and no matching Rank with other ID (starting with 4 or 5) then show them as result.
So My Output should look like
ID Rank
98523 3
92147 4
99999 10
How can I use case statement in where clause to filter the data?
If I understand correctly, you want to select only those ID that begin with a 9, and have a rank that is not also the rank of (another) ID that begins with 4 or 5. Is that correct?
The query below is for the case ID is of string data type (although it will work OK, probably, if ID is numeric data type - through implicit conversion).
select *
from your_table
where id like '9%'
and rank not in (
select rank
from your_table
where substr(id, 1, 1) in ('4', '5')
)
;
One option would be using COUNT() analytic function along with a conditional aggregation such as
WITH t2 AS
(
SELECT SUM(CASE WHEN SUBSTR(id,1,1) IN ('5','9') OR
SUBSTR(id,1,1) IN ('4','9') THEN 1 END ) OVER
(PARTITION BY Rank) AS count, t.*
FROM t -- your original table
)
SELECT id, rank
FROM t2
WHERE count = 1
Demo
You can use an analytic function to only query the table once:
SELECT id,
rank
FROM (
SELECT t.*,
COUNT( CASE WHEN id LIKE '4%' OR id LIKE '5%' THEN 1 END )
OVER ( PARTITION BY Rank )
AS num_match
FROM table_name t
WHERE id LIKE '4%'
OR id LIKE '5%'
OR id LIKE '9%'
)
WHERE id LIKE '9%'
AND num_match = 0;
Which, for the sample data:
CREATE TABLE table_name ( ID, Rank ) AS
SELECT 45689, 1 FROM DUAL UNION ALL
SELECT 54789, 2 FROM DUAL UNION ALL
SELECT 98765, 1 FROM DUAL UNION ALL
SELECT 96541, 2 FROM DUAL UNION ALL
SELECT 98523, 3 FROM DUAL UNION ALL
SELECT 92147, 4 FROM DUAL UNION ALL
SELECT 96741, 2 FROM DUAL UNION ALL
SELECT 99999, 10 FROM DUAL;
Outputs:
ID | RANK
----: | ---:
98523 | 3
92147 | 4
99999 | 10
db<>fiddle here

SQL Weird Grouping - Matching rows sharing common values for either of two columns?

I am trying to use a recursive CTE to add a Group ID column to my data for mapping purposes. I am using the code here (SQL Server Weird Grouping Scenario by multiple columns and OR), but the output from this code is not working as intended.
I have a SQL Server table #cache_resale_tbl, and I would like to add a Group ID column that buckets the rows into groups.
Table Name: #cache_resale_tbl
Columns: Key ID, Purchase Order Number ("col1"), Ticket Number ("col2")
I want to add a column which has a group ID, and all rows having the same PO Number OR Ticket Number get the same group ID.
Here is the code I am using:
with g (rootid, previd, level, KeyID, col1, col2) as
(
select
KeyID, 0, 1, KeyID, col1, col2
from
#cache_resale_tbl
union all
select
g.rootid, g.KeyID, g.level + 1, v.KeyID, v.col1, v.col2
from
g
join
#cache_resale_tbl v on v.col1 = g.col1 or v.col2 = g.col2
where
v.KeyID > g.KeyID
),
m (KeyID, rootid) as
(
select
KeyID, min(rootid)
from
g
group by
KeyID
)
select
v.KeyID, v.col1, v.col2,
cast(min(rootid) as varchar(50)) as 'Group ID'
from
m
inner join
#cache_resale_tbl v on v.KeyID = m.KeyID
group by
v.KeyID, v.col1, v.col2;
Sample Input for #cache_resale_tbl:
KeyID col1 col2
-----------------------
1 PO25303309 255207
2 PO25303304 257459
3 PO25303305 257459
4 PO25303306 257459
5 PO25303307 257459
6 PO25303309 257459
Code output:
KeyID col1 col2 Group ID
----------------------------
1 PO25303309 255207 1
2 PO25303304 257459 2
3 PO25303305 257459 2
4 PO25303306 257459 2
5 PO25303307 257459 2
6 PO25303309 257459 1
Desired output:
KeyID col1 col2 Group ID
----------------------------
1 PO25303309 255207 1
2 PO25303304 257459 1
3 PO25303305 257459 1
4 PO25303306 257459 1
5 PO25303307 257459 1
6 PO25303309 257459 1
My expected output would be that the Group ID column returns all the same number for these rows. The last 5 rows should all have the same Group ID because they have the same col2 value. And the first ticket also belongs to this group because row 1 and 6 have the same col1 value. Any row that has the same col1 or col2 value should be in the same group ID. Therefore, my desired output is to map these all into one group, which the code I'm using doesn't seem to do.
Any help on this would be greatly appreciated :) Thanks!
I believe this does what is originally asked in the question with one caveat. Orders not repeated in either col1 or col2 are grouped together (uncomment line union all select 8, 'PO25303311', 331503 in the CTE for an example).
;with cache_resale_tbl as(
select
1 KeyID, 'PO25303309' col1, 255207 col2
union all select 2, 'PO25303304', 257459
union all select 3, 'PO25303305', 257459
union all select 4, 'PO25303306', 257459
union all select 5, 'PO25303307', 257459
union all select 6, 'PO25303309', 257459
union all select 7, 'PO25303310', 331502
--union all select 8, 'PO25303311', 331503
)
,CountRepeatVal AS(
select
cache_resale_tbl.*
,CntCol1 = COUNT(*) over (partition by col1)
,CntCol2 = COUNT(*) over (partition by col2)
from cache_resale_tbl
)
,Grouped AS(
select
CountRepeatVal.*
,Groups = case when (CountRepeatVal.CntCol1 > 1 OR CountRepeatVal.CntCol2 > 1) then 0 else 1 end
from CountRepeatVal
)
select
--Grouped.*
Grouped.KeyID
,Grouped.col1
,Grouped.col2
,GROUP_ID = DENSE_RANK() OVER(ORDER BY Groups)
FROM Grouped
Here's the db<>fiddle

fetch record as in order passed for IN condition in oracle

I want to fetch the records in order passed for IN condition.
select * from table where id in(6,3,7,1);
is returning the rows as
id name
1 abc
3 xy
6 ab
7 ac
but I want to display the records in same orders as ids passed in condition in Oracle
id name
6 ab
3 xy
7 ac
1 abc
Please help me in fetching the records in same order as in condition ids in oracle. The values in IN condition may change dynamically.
You can do this with a case statement in the order by clause or using a join.
select *
from table
where id in(6,3,7,1)
order by (case id when 6 then 1 when 3 then 2 when 7 then 3 when 1 then 4 end);
Or:
with ids as (
select 6 as id, 1 as ordering from dual union all
select 3 as id, 2 as ordering from dual union all
select 7 as id, 3 as ordering from dual union all
select 1 as id, 4 as ordering from dual
)
select *
from table t join
ids
on t.ids = ids.id
order by ids.ordering;
Note that you don't need the in in this case, because the join does the filtering.
you can use trick
select * from table where id in(6,3,7,1) order by case when id = 6 then 1
id = 3 then 2
id = 7 then 3
id = 1 then 4
end

Get next row value based on returned list of rows

In Oracle, suppose I have a query that returns the following list:
ID Sequence#
12 1
15 3
25 5
All I know in this case is the ID of some row (let's suppose 12), I need to return the ID of a row with the next sequence number which in this case is 3 (id = 15)
How can I do it? I know there's a Oracle function lead, but I wasn't able to successfully impement is.
Yes, you can use lead function to get the next value. Here is an example of how it can be done.
-- sample of data from your question
SQL> with t1(ID, Sequence#) as
2 (
3 select 12, 1 from dual union all
4 select 15, 3 from dual union all
5 select 25, 5 from dual
6 )
7 select *
8 from (select id
9 , sequence#
10 , lead(sequence#) over(order by id) next_sequence#
11 , lead(id) over(order by id) next_id#
12 from t1
13 )
14 where id = 12
15 ;
ID SEQUENCE# NEXT_SEQUENCE# NEXT_ID#
---------- ---------- -------------- ----------
12 1 3 15
SELECT * FROM table1 where ID in (SELECT min(ID) FROM table1 WHERE ID > 12)
Select sequence from my_ table where id=(select min(id) from my_table where sequence> 1)
Replace (1) in the above query with any value that you are searching for its next

Select data from table with update if particular row does not exist

I have a simple table TBL consisting of two columns Err_type and Val.
Need to select all date from it. Seems to be simple, but it gets uglier when particular row does not exist.
with cte as (
select TBL.Err_type, TBL.Val from TBL
where TBL.Err_type = 4 or TBL.Err_type = 2
)
select * from cte
There are possibilities that "4" or "2" might not exist in given datetime range. So i need to insert the missing row ("4" or "2" for Err_type and "0" for Val) and then get the table.
e.g.
Err_type | Val
---------------
4 | 50
2 | 0
instead of
Err_type | Val
---------------
4 | 50
Use following sql that will check for existence of record and if not found then insert.
WITH cte
AS (SELECT *
FROM TBL
WHERE TBL.Err_Type IN ( 4, 2 )
UNION
SELECT 4,
0
WHERE NOT EXISTS (SELECT 1
FROM TBL
WHERE TBL.Err_Type = 4)
UNION
SELECT 2,
0
WHERE NOT EXISTS (SELECT 1
FROM TBL
WHERE TBL.Err_Type = 2))
SELECT *
FROM cte