Is there a loop function which can automatize this? - sql

I have these lines of code which you can find below and I want to automatize this (most probably using a loop function) by just giving the input: 'CITY', 'COUNTY', 'PARTNERS', 'PRODUCT'. Is there any way to do this?
Also the names of temporary tables ('CUSTOMERS_MND_0', CUSTOMERS_MND_1', 'CUSTOMERS_MND_2', 'CUSTOMERS_MND_3', 'CUSTOMERS_MND_4') are not important, so those can be renamed as the variable names.
The issue I'm facing is that "UNIQUE_KEY" is not unique and I need to have it unique in the final db. Please find an example.
Initial DB:
UNIQUE_KEY
CITY
COUNTY
PARTNERS
PRODUCT
111
VIENNA
A
W
1
111
NAPLES
B
X
7
112
VIENNA
B
Y
3
113
NAPLES
B
W
4
113
NAPLES
A
W
4
114
VIENNA
A
W
1
115
VIENNA
B
W
4
115
NAPLES
A
W
4
115
VIENNA
B
X
7
115
VIENNA
B
Y
3
116
NAPLES
B
W
4
116
NAPLES
A
W
4
116
VIENNA
A
W
1
FINAL DB:
UNIQUE_KEY
CITY
COUNTY
PARTNERS
PRODUCT
111
VIENNA
A
W
1
112
VIENNA
B
Y
3
113
NAPLES
B
W
4
114
VIENNA
A
W
1
115
VIENNA
B
Y
3
116
VIENNA
A
W
1
SELECT AA.*
INTO #CUSTOMERS_MND_1
FROM #CUSTOMERS_MND_0 AA
INNER JOIN (SELECT UNIQUE_KEY,
MAX(CITY) AS MAXCITY
FROM #CUSTOMERS_MND_0
GROUP BY UNIQUE_KEY) BB ON AA.UNIQUE_KEY = BB.UNIQUE_KEY
AND AA.CITY = BB.MAXCITY;
DROP TABLE #CUSTOMERS_MND_0;
SELECT AA.*
INTO #CUSTOMERS_MND_2
FROM #CUSTOMERS_MND_1 AA
INNER JOIN (SELECT UNIQUE_KEY,
MAX(COUNTY) AS MAXCOUNTY
FROM #CUSTOMERS_MND_1
GROUP BY UNIQUE_KEY) BB ON AA.UNIQUE_KEY = BB.UNIQUE_KEY
AND AA.COUNTY = BB.MAXCOUNTY;
DROP TABLE #CUSTOMERS_MND_1;
SELECT AA.*
INTO #CUSTOMERS_MND_3
FROM #CUSTOMERS_MND_2 AA
INNER JOIN (SELECT UNIQUE_KEY,
MAX(PARTNERS) AS MAXPARTNERS
FROM #CUSTOMERS_MND_2
GROUP BY UNIQUE_KEY) BB ON AA.UNIQUE_KEY = BB.UNIQUE_KEY
AND (AA.PARTNERS = BB.MAXPARTNERS
OR AA.PARTNERS IS NULL
AND BB.MAXPARTNERS IS NULL);
DROP TABLE #CUSTOMERS_MND_2;
SELECT AA.*
INTO #CUSTOMERS_MND_4
FROM #CUSTOMERS_MND_3 AA
INNER JOIN (SELECT UNIQUE_KEY,
MAX(PRODUCT) AS MAXPRODUCT
FROM #CUSTOMERS_MND_3
GROUP BY UNIQUE_KEY) BB ON AA.UNIQUE_KEY = BB.UNIQUE_KEY
AND (AA.PRODUCT = BB.MAXPRODUCT
OR AA.PRODUCT IS NULL
AND BB.MAXPRODUCT IS NULL);
DROP TABLE #CUSTOMERS_MND_3;
It works, but for more joins it is not time efficient.

my guess is you want the max city per unique key, within that city the max county, within that county the max partners and within that partner the max product in which case generating a row number and selecting row number 1 gives the same result as your code
create table #CUSTOMERS_MND_0
(unique_key int,city varchar(10),county varchar(10),partners varchar(10),product int);
go
insert into #CUSTOMERS_MND_0 values
(111,'vienna','a','w',7),(111,'naples','b','x',7),(111,'vienna','b','w',6),(111,'vienna','b','x',5)
go
with cte as
(select *, row_number() over (partition by unique_key order by city desc , county desc, partners desc,product desc) rn
from
#CUSTOMERS_MND_0
)
select * from cte where rn = 1;
your code plus
select * from #CUSTOMERS_MND_3
unique_key city county partners product
----------- ---------- ---------- ---------- -----------
111 vienna b x 5
my code
unique_key city county partners product rn
----------- ---------- ---------- ---------- ----------- --------------------
111 vienna b x 5 1
Now we have simplified code we can think about automation. You say you want to supply known columns as part of this process but unique key will always be required and source tables is known so--see https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=355f06fb7d51ba8fed9ea4e6d1e23d07 for an example of how using a temp table to hold the columns and the priority order in this case by identity. Then read up on dynamic sql..

Related

I have 2 tables and I need to use SQL to return non matching data/columns

I have 2 tables with same number of columns. tablea has 5 rows and tableb has 4 rows with 2 matching rows and 3 non matching rows. I need to return all 3 non matching columns/data
The query below only returns the non matching column in table and not all the non matching columns. I'am trying to return non matching rows 3,4,5 . see table below
select *
from tablea
where not exists (select * from tableb
where tableb.id = tablea.id)
Table a:
id contact name address city postalcode country
———————————————
1 ab aa 123 hd 12 usa
2 as bb 321 hh 23 mex
3 av cc 571 hn 123 mex
4 as ww 457 bd 57 uk
5 chat xx 23 dh 123 fin
Table b:
id contact name address city postalcode country
————————————————
1 ab aa 123 hd 12 usa
2 as bb 321 hh 23 mex
3 ad ah 3200 res 321 mex
4 ash bb 457 hsj 1223 uk
I am not 100% sure on what rows you want exactly, as your text is kinda contradictionary, but if you want the 3 not matching rows from tableb this is what you need to do:
SELECT * FROM tableb WHERE customerid NOT IN (SELECT customerid FROM tablea)
If you want the ones not matching from tablea, you just need to change tablea with tableb and vice versa.
If you want all not matching, combine both options:
SELECT * FROM tablea, tableb WHERE tablea.customerid NOT IN (SELECT customerid from tableb) AND tableb.customerid NOT IN (SELECT customerid from tablea)

How to make a view with 2 tables linked by another table?

I have 3 table
driver
id
first name
last_name
age
1
Joe
doe
26
2
John
smith
31
...
...
...
...
Location
id
name
zipcode
country
1
London
250 329
UK
2
NY
00501
USA
...
...
...
...
Travel
id
Person_id
location_id
nb_passenger
1
1
1
2
2
1
1
4
3
2
2
3
4
1
2
2
5
2
1
3
...
...
...
...
I'm looking to create a view to get the total number of passengers by destination and by driver, but it's taking the same row multiple times
I tried something like that but it didn't work
SELECT location.id AS location_id,
location.name AS location_name,
d.id AS driver_id,
d.name AS driver_name,
sum(tr.passenger) as passenger_count
FROM location
LEFT JOIN travel tr_0 ON location.id = tr_0.location_id
LEFT JOIN driver d ON tr_0.driver_id = d.id
LEFT JOIN travel tr ON location.id = tr.location_id AND tr.driver_id = d.id
GROUP BY location.id, location.name,...;
I'm sure it's simple but I'm not on the right way

Unique coverage between a pair of values in SQL

I want to get a distinct list of Item_IDs per vendor pair, e.g. (A,B), (A,C), (B,C)
I have a table like this:
Item_ID | vendor
123 A
123 B
133 B
456 C
I want to list ALL of the distinct Item_IDs between each pair of vendors, like below. Essentially, I want to know all of the Item_IDs which are "covered" (or present) between a pair of vendors.
Vendor1 | Vendor 2 | Item_ID
A B 123
A B 133
A C 123
A C 456
B C 123
B C 133
B C 456
I have tried using a self join, to get 2 vendors side by side, but struggling on how to list out the Item_IDs per pair.
Here is what I have so far:
select
distinct a.vendor as vendor1, b.vendor as vendor2
from table a
join table b on a.vendor != b.vendor
and a.vendor >= b.vendor -- to remove duplicate combinations
The following query works in SQL Server 2019 but I don't have the chance of testing it in Azure.
You can do:
with
v as (select distinct vendor as vendor from t)
select
a.vendor as vendor1,
b.vendor as vendor2,
x.item_id
from v a
join v b on b.vendor > a.vendor
cross apply (
select distinct item_id
from t
where t.vendor = a.vendor or t.vendor = b.vendor
) x
order by a.vendor, b.vendor
Result:
vendor1 vendor2 item_id
-------- -------- -------
A B 123
A B 133
A C 123
A C 456
B C 123
B C 133
B C 456
See running example at db<>fiddle.

Query to join two tables using two different columns from the first table

I have two tables .
Table A:
Table A ID Table Name owner1ID owner2ID
1 Work1 85 91
2 Work2 86 92
3 Work3 87 93
4 Work4 88 94
5 Work5 89 95
6 Work6 90 96
Table B:
OwnerID 0WNERFIRSTNAME 0WNERlASTNAME
85 A M
86 B N
87 C O
88 D P
90 E Q
91 F R
89 G S
92 H T
86 I U
94 J V
93 K W
95 L X
Can you please help me out in getting a query where i need the table which contains TABLEID OWNERFIRSTNAME and OWNERSECONDNAME.
Expected output:
TableAID 0WNER1FIRSTNAME 0WNER1LASTNAME 0WNER2FIRSTNAME 0WNER2LASTNAME
1 A M F R
You need to join on to TableB twice.
That means you need to give each instance of the table an alias, so you can differentiate which instance you're referring to...
SELECT
TableA.TableAID,
TableB1.0WNERFIRSTNAME AS 0WNER1FIRSTNAME,
TableB1.0WNERlASTNAME AS 0WNER1LASTNAME,
TableB2.0WNERFIRSTNAME AS 0WNER2FIRSTNAME,
TableB2.0WNERlASTNAME AS 0WNER2LASTNAME
FROM
TableA
INNER JOIN
TableB TableB1
ON TableB1.OwnerID = TableA.owner1ID
INNER JOIN
TableB TableB2
ON TableB2.OwnerID = TableA.owner2ID
P.S. Don't Spell 0WNERFIRSTNAME with a ZERO, Spell it OWNERFIRSTNAME!
While MatBaile's answer is the most common practice, your own example shows some problems. First is that we lose info about table 6 for which second owner is not found in second table. This can be easily corrected with left join:
select a.id, a.table_name,
b1.OwnerFirstName O1FN, b1.OwnerLastName O1LN,
b2.OwnerFirstName O2FN, b2.OwnerLastName O2LN
from a
left join b b1 on b1.OwnerId = a.Owner1Id
left join b b2 on b2.OwnerId = a.Owner2Id
What gives us:
ID TABLE_NAME O1FN O1LN O2FN O2LN
---------- ---------- ---- ---- ---- ----
1 Work1 A M F R
2 Work2 I U H T <-- two first owners
2 Work2 B N H T <-- two first owners
4 Work4 D P J V
3 Work3 C O K W
5 Work5 G S L X
6 Work6 E Q <-- null second owner
And second problem - for table 2 we got two entries, because in your example there are two owners with id = 86. I suspect that this is typo, but this can happen in similiar cases. You can leave it as is, or take only last row (if owner changed and you have info about this in some date column), or you can list all owners using listagg(), or take max value. Things are worse when there are more rows connected to 1. and 2. owner, your output is multiplied.
As a curiosity here is unpivot-pivot solution. In this case this query looks more complicated, but if there were 10 columns you had to do 10 joins and in this query only lists of columns requires change.
select *
from (
select id, table_name, type, ownerfirstname, ownerlastname
from (select * from a unpivot (ownerId for type in (owner1ID as 1, owner2ID as 2))) a
join b using (ownerId))
pivot (listagg(ownerfirstname||' '||ownerlastname, ', ') within group (order by null) owner
for type in (1, 2))
SQL Fiddle demo
ID TABLE_NAME 1_OWNER 2_OWNER
---------- ---------- ---------- ----------
1 Work1 A M F R
2 Work2 B N, I U H T <-- listagg() used to aggregate data
3 Work3 C O K W
4 Work4 D P J V
5 Work5 G S L X
6 Work6 E Q

Simply by the Query

Table name is group. Column name is groupno,name,grouprefno,detail,undergroupno
Sample data of group
groupno name grouprefno detail undergroupno
1 A 001 abc 0
2 B 002 cde 0
3 AA 001001 abc 1
4 AC 001002 abc 1
5 AAA 001001001 DDD 3
6 DDD 001001002 ddd 3
7 www 001002001 223 4
8 eee 001002002 222 4
Now i want to get rows which name's are AA, AC and which are comes under the AA,AC
So i tried like this
select no from group where substring(grouprefno,1,
(select length(grouprefno) from group where name ='AA'
))=(select grouprefno from group
where name ='AA' ) union all select no from group where substring(grouprefno,1,
(select length(grouprefno) from group where name ='AC'
))=(select grouprefno from group
where groupname ='AC' )
Its Work Fine, But i want another solution because it has 2 sub query's in side of single query. It has any other feasible solution?
Am using postgresql 9.1
Try:
WITH q AS(
SELECT *
FROM Table1
WHERE name IN ('AA','AC')
)
SELECT * FROM q
UNION ALL
SELECT * FROM Table1 t
WHERE t.undergroupno IN (
SELECT groupno FROM q
)
Demo: http://sqlfiddle.com/#!12/fce65/3