SQL select Name entries for which a certain requirement is NEVER fulfilled - sql

I need to select Name entries for which none of the rows fulfills a certain requirement. This is best described as an example- lets consider the following table:
Name Number ID
A 1 2
A 2 2
B 1 2
B 2 3
C 3 3
The requirement would be that Number=ID. For the name B this is never the case, so I would like to return the Name B.
Name Number ID
A 1 2
A 2 2 <---- fulfills requirement for A
B 1 2
B 2 3
C 3 3 <---- fulfills requirement for C
Is this possible in SQL?

You can use a NOT EXISTS clause
select * from Table1 t1
where not exists (select null
from Table1
where t1.Name = Name
and Number = Id)
If you just want the names which don't fulfill the requirement, just change the select to
select distinct t1.Name
see SqlFiddle with both versions.

Try this
Select Name
from table
where name not in (Select distinct name from table where number = id )

Related

Identify rows containing repeating customers and assigning them new id as per serial number generated in sql

I have a table
id
repeat customer id
store
date
1
A
07-19-22
2
A
07-19-22
3
A
07-19-22
id
repeat customer id
store
date
1
B
07-19-22
2
B
07-19-22
3
1
B
07-19-22
4
B
07-19-22
and more tables from other store
The problem here is
all stores start with id 1
repeat customer have new id in id column and their original id is retained in repeat customer id column
I have to concatenated all the tables and also keep track of repeating customer for analytics. I have joined all tables using UNION ALL and also created a dummy id column using SELECT ROW_NUMBER() OVER(ORDER BY (SELECT 1)) AS NEW_ID, * FROM CTE, but I have no clue how to capture and assign value to repeat customer id such that I get the table as below
NEW_ID
id
new_repeat_customer_id
repeat customer id
store
date
1
1
A
07-19-22
2
2
A
07-19-22
3
3
A
07-19-22
4
1
B
07-19-22
5
2
B
07-19-22
6
3
4
1
B
07-19-22
7
4
B
07-19-22
The best way to incorporate it, would be to use Alphanumeric String as NEW_ID, and concat STORE and ID to create NEW_ID. For example A_000000001. In that way you can add similar STORE to REPEAT_CUSTOMER_ID as well.
So in this case, instead of NEW_ID=6, you would have NEW_ID=B_000000003 and REPEAT_CUSTOMER_ID would become B_000000001.
But in case that is not possible, you can use query like below to get the output
DB Fiddle Query
with CTE as
(
select * from STORE1
UNION ALL
select * from STORE2
)
,CTE2 as
(SELECT ROW_NUMBER() OVER(ORDER BY (SELECT 1)) AS NEW_ID,t.* from CTE t)
,REPEAT_ID as
(select NEW_ID,ID,REPEAT_CUSTOMER_ID,STORE from CTE2 where REPEAT_CUSTOMER_ID is not null)
,REPEACT_CUSTOMER_ID as
(select c.NEW_ID as NEW_REPEAT_CUSTOMER_ID,r.NEW_ID
from REPEAT_ID r
left join CTE2 c
on c.ID=r.REPEAT_CUSTOMER_ID and c.STORE=r.STORE
)
select c.* , n.NEW_REPEAT_CUSTOMER_ID
from CTE2 c
left join REPEACT_CUSTOMER_ID n
on c.NEW_ID=n.NEW_ID
https://dbfiddle.uk/?rdbms=sqlserver_2014&fiddle=cbe63994b10f9e3b0eff53b0c89d463a
SO basically you have to separate rows where REPEATE customer is present and join it with main table query.

Create multiple rows based on 1 column

I currently have a table with a quantity in it.
ID Code Quantity
1 A 1
2 B 3
3 C 2
4 D 1
Is there anyway to write a sql statement that would get me
ID Code Quantity
1 A 1
2 B 1
2 B 1
2 B 1
3 C 1
3 C 1
4 D 1
I need to break out the quantity and have that many number of rows
Thanks
Here's one option using a numbers table to join to:
with numberstable as (
select 1 AS Number
union all
select Number + 1 from numberstable where Number<100
)
select t.id, t.code, 1
from yourtable t
join numberstable n on t.quantity >= n.number
order by t.id
Online Demo
Please note, depending on which database you are using, this may not be the correct approach to creating the numbers table. This works in most databases supporting common table expressions. But the key to the answer is the join and the on criteria.
One way would be to generate an array with X elements (where X is the quantity). So for rows
ID Code Quantity
1 A 1
2 B 3
3 C 2
you would get
ID Code Quantity ArrayVar
1 A 1 [1]
2 B 3 [1,2,3]
3 C 2 [2]
using a sequence function (e.g, in PrestoDB, sequence(start, stop) -> array(bigint))
Then, unnest the array, so for each ID, you get a X rows, and set the quantity to 1. Not sure what SQL distribution you're using, but this should work!
You can use connect by statement to cross join tables in order to get your desired output.
check my solution it works pretty robust.
select
"ID",
"Code",
1 QUANTITY
from Table1, table(cast(multiset
(select level from dual
connect by level <= Table1."Quantity") as sys.OdciNumberList));

Get duplicate on single column after distinct across multiple columns in SQL

I have a table that looks like this:
name | id
-----------
A 1
A 1
B 2
C 1
D 3
D 3
F 2
I want to return id's 1 and 2 because they are duplicate on names. I don't want to return 3, because it is distinct for D 3.
Basically, I'm thinking of doing a query to first get a distinct pairing, so the above reduces to
name | id
-----------
A 1
B 2
C 1
D 3
F 2
And then doing a duplicate find on the id column. However, I'm struggling to find the correct syntax to construct that query.
You should be able to get the result you want by using a GROUP BY along with a HAVING clause that counts the distinct names. The HAVING clause will filter for those ids that have more than one distinct name:
select id
from Table1
group by id
having count(distinct name) > 1
Here is a demo

Select unique subsets

I have a table like in example below.
SQL> select * from test;
ID PARENT_ID NAME
1 1 A
2 1 B
3 2 A
4 2 B
5 3 A
6 3 B
7 3 C
8 4 A
What I need is to get all unique subsets of names ((A,B), (A,B,C), (A)) or exclude duplicate subsets. You can see that (A,B) is twice there, one for PARENT_ID=1 and one for 2.
I want to exclude such duplicates:
ID PARENT_ID NAME
1 1 A
2 1 B
5 3 A
6 3 B
7 3 C
8 4 A
You can use DISTINCT to only return different values.
e.g.
SELECT DISTINCT GROUP_CONCAT(NAME SEPARATOR ',') as subsets
FROM TABLE_1
GROUP BY PARENT_ID;
SQL Fiddle
I have used 'group_concat' assuming you are using 'Mysql'. The equivalent function in Oracle is 'listagg()'. you can see it in action here in SQL fiddle
Here is the solution:-
Select a.* from
test a
inner join
(
Select nm, min(parent_id) as p_id
from
(
Select Parent_id, group_concat(NAME) as nm
from test
group by Parent_ID
) a
group by nm
)b
on a.Parent_id=b.p_id
order by parent_id, name

Count number of not exist in child table

Essentially what I'm trying to do is count the number of rows something doesn't exist in an audit/history table. I'd like the following query to return a count of one per detail. Currently it gives me one per row in the history table.
--Detail Table
ID DETAIL_GROUP
1 A
2 B
3 B
--Detail History Table
DETAIL_ID_FK VALUE1
1 NOT_MATCH
1 NOT_MATCH
2 MATCH
2 NOT_MATCH
3 MATCH
3 NOT_MATCH
SELECT D.DETAIL_GROUP, COUNT(*)
FROM DETAIL D
WHERE (NOT EXISTS(
SELECT NULL
FROM DETAIL_HISTORY HI
WHERE HI.D_ID_FK = D.ID
AND HI.VALUE1 = 'MATCH'))
GROUP BY D.DETAIL_GROUP;
I'd like to see the following result:
DETAIL_GROUP COUNT(*)
A 1
but I'm receiving the following result:
DETAIL_GROUP COUNT(*)
A 2
Thank you in advance for any assistance provided.
Assuming that your detail table is as follows:
D_ID VALUE1
1 MATCH
1 NOT_MATCH
2 MATCH
2 NOT_MATCH
3 MATCH
3 NOT_MATCH
The below query:
SELECT d.detail_group, count(*)
FROM detail d
JOIN detail_history dh ON dh.d_id = d.id
WHERE dh.value1 = 'MATCH'
GROUP BY d.detail_group
Would produce:
DETAIL_GROUP COUNT(*)
A 1
B 2
The above query creates the groups matching the ids and then goes into each group and restricts the items based on value1.