Using a Selected table for two sets of joins - sql

I'm rationalising some old SQL tables that exist at a lot of remote sites, so I need to build a query that will make new good tables out of the bad old ones. So for this, we have table1 which has the columns DataGroup and Case1 as nvarchar, but these are enums in the application, so I've made new tables to store the enums, but I need to get the IDs. Unfortunately, we need to store all of the enums for this table in a single table, so the ExData table contains 4 columns: id, name, ExGroupId and DataGroupId.
As DataGroup in table1 is text, we need to look that up for the int id as well from a kvp table DataGroupTable
This is the query I have so far:
SELECT
<Other Columns>,
t1.ExDataId AS Case1
FROM
table1
LEFT JOIN (
SELECT
DataGroupTable.name AS dataGroup,
ExData.id AS ExDataId,
ExData.name AS ExDataName,
ExGroup.name AS ExGroupName
FROM
ExData
LEFT JOIN DataGroupTable ON DataGroupTable.id = ExData.dataGroupId
LEFT JOIN ExGroup ON ExGroup.id = ExData.ExGroupId
) t1 ON t1.dataGroup = table1.DataGroup
AND t1.ExGroupName = 'case1'
AND t1.ExDataName = table1.Case1
GO
... But while this works to retrieve Case1, how would I go about getting Case2?
I have 7 cases to handle, and whilst I could solve this with liberal copy-pasting, that is far from elegant.
Additionally, this is all going into an INSERT statment, so ideally this should return Case1, Case2 etc as ExDataId's
Please help.
Sample Data as requested, All id's will start from 0, but I have made all of the below unique for clarity.
table1:
DataGroup Case1 Case2 Case3 <Other Columns>
ABCD bob bob chris 1
ABCD pete gary chris 2
EFGH bob mike rod 3
DataGroupTable:
id name
11 ABCD
12 EFGH
ExGroup:
id name
21 case1
22 case2
23 case3
ExData:
id name ExGroupId dataGroupId
31 bob 21 11
32 pete 21 11
33 bob 21 12
34 bob 22 11
35 gary 22 11
36 mike 22 12
37 chris 23 11
38 rod 23 12
Ideal Result:
<Other Columns> Case1 Case2 Case3
1 31 34 37
2 32 35 38
3 33 36 38

How about a Common Table Expression ?
WITH ExDataCTE AS (
SELECT
DataGroupTable.name AS dataGroup,
ExData.id AS ExDataId,
ExData.name AS ExDataName,
ExGroup.name AS ExGroupName
FROM
ExData
LEFT JOIN DataGroupTable ON DataGroupTable.id = ExData.dataGroupId
LEFT JOIN ExGroup ON ExGroup.id = ExData.ExGroupId)
SELECT
<Other Columns>,
t1.ExDataId AS Case1,
t2.ExDataId AS Case2,
t3.ExDataId AS Case3
FROM
table1
LEFT JOIN ExDataCTE t1 ON (t1.dataGroup = table1.DataGroup
AND t1.ExGroupName = 'case1'
AND t1.ExDataName = table1.Case1)
LEFT JOIN ExDataCTE t2 ON (t2.dataGroup = table1.DataGroup
AND t2.ExGroupName = 'case2'
AND t2.ExDataName = table1.Case2)
LEFT JOIN ExDataCTE t3 ON (t3.dataGroup = table1.DataGroup
AND t3.ExGroupName = 'case3'
AND t3.ExDataName = table1.Case3)

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)

SQL Server : multiple rows single line

I would like to get the representation of one record based on the primary key value from multiple tables. As shown below, each table can have multiple values based on this primary key value.
TABLE-1
ID
NAME
1
AA
2
BB
3
CC
4
DD
5
EE
TABLE-2
ID
SCHOOL
AUT
1
11
A
2
11
A
2
12
B
3
11
A
4
12
A
4
13
B
5
13
A
TABLE-3
ID
TC
1
101
2
102
2
103
2
104
3
105
4
106
4
107
5
108
The result below is the value obtained with an OUTER JOIN.
SELECT
T1.ID, T2.SCHOOL, T3.TC, T2.AUT
FROM
T1
LEFT OUTER JOIN
T2 ON T1.ID = T2.ID
LEFT OUTER JOIN
T3 ON T1.ID = T3.ID
ORDER BY
T1.ID ASC
ID
SCHOOL
TC
AUT
1
11
101
A
2
11
102
A
2
12
102
B
2
11
103
A
2
12
103
B
2
11
104
A
2
12
104
B
3
11
105
A
4
12
106
A
4
13
106
B
4
12
107
A
4
13
107
B
5
13
106
A
How can I get the result like below?
ID
SCHOOL
TC1
TC2
TC3
1
11
101
2
11
102
103
104
3
11
105
4
12
106
107
5
13
108
The important thing here is that in the result value, SCHOOL only shows that AUT is 'A'.
I would appreciate it if you let me know your query.
It looks, from your desired results, you just need to use row_number in combination with a conditional aggregate. Your sample data seems a little inadequate, I can't see any requirement for table1 at all.
Try the following:
with t as (
select t2.id,t2.school,t3.tc, Row_Number() over(partition by t2.id order by t3.tc) col
from t2 join t3 on t2.id=t3.id
where aut='A'
)
select id,school,
max(case when col=1 then tc end) TC1,
max(case when col=2 then tc end) TC2,
max(case when col=3 then tc end) TC3
from t
group by id, school
Example SQL Fiddle
SELECT
T1.ID, T2.SCHOOL,
GROUP_CONCAT(T3.TC),
GROUP_CONCAT(T2.AUT)
FROM
T1
LEFT OUTER JOIN
T2 ON T1.ID = T2.ID
LEFT OUTER JOIN
T3 ON T1.ID = T3.ID
GROUP BY
T1.ID, T2.SCHOOL
WHERE
T2.AUT = ‘A’
ORDER BY
T1.ID ASC
Notice that GROUP_CONCAT concatenates the values in the row.
EDIT: oh my, haven't seen that it's a SQL Server question!
Just replace GROUP_CONCAT with STRING_AGG if you’re using SQL Server 2017 or newer.

Joining on optional

I have 2 tables:
Table1 - Criteria
Office_ID Bus_Stream Bus_Criteria Crit_Value
1 ABC 0 20
1 ABC 1 21
1 ABC 2 7
2 ABC 0 15
2 ABC 1 12
2 ABC 2 21
3 XYZ 1 17
3 XYZ 2 3
Table2 - Limit
Bus_Stream GroupID TypeID SubgroupID Bus_Limit
ABC 20 21 7 50
ABC 15 12 21 100
XYZ 99 17 3 120
I need to create a join that allows me to pull back:
Result
Bus_Stream Office_ID GroupID TypeID SubgroupID Bus_Limit
ABC 1 20 21 7 50
ABC 2 15 12 21 100
XYZ 3 (null) 17 3 120
Essentially, I need to join Table1.Crit_Value based on the following:
Table1.Bus_Criteria Table2
0 GroupID
1 TypeID
2 SubGroupID
with the added complication that if one or two of the 0/1/2 values from Bus_Criteria is missing, the joins will still occur on the remaining criteria.
I have tried a number of combinations of AND/OR on the join to no avail.
Any ideas folks?
This may be what you're after.. use a case statement on the join.
The problem here is your data in t2 isn't normalized, you could also unpivot the 3 data columns in t2 so the join is more natural.
SELECT T2.Bus_Stream, T1.Office_ID, T2.GroupID, T2.TypeID, T2.SubGroupId, T2.bus_Limit
FROM T1
INNER JOIN T2
on T1.Bus_Stream = T2.Bus_Stream
and T1.Crit_value = case when T1.Bus_Critiera = 0 then T2.GroupID
when T1.Bus_Critiera = 1 then T2.TypeID
when T1.Bus_Critiera = 2 then T2.SubGroupID
end
Did you try something like this?
SELECT
t1.*, t2.*
FROM Table1 t1
INNER JOIN Table2 t2 ON
t1.Bus_Stream = t2.Bus_Stream AND
CASE
WHEN t1.Bus_Criteria = 0
THEN t2.GroupID = t1.Crit_Value
WHEN t1.Bus_Criteria = 1
THEN t2.TypeID = t1.Crit_Value
ELSE
t2.SubGroupID = t1.Crit_Value
END

Please advise SQL Update issue

I have a SQL database with two tables
TableA (ID, State, Value)
1 England 20
2 France 50
3 USA 40
4 ........
5 ........
and
TableB (ID, username, age, stateID)
1 John 15 1
2 Adam 20 2
3 Jane 40 3
4 Scott 50 1
5 Edwin 60 2
6 Alex 20 3
7 Olsen 30 1
8 ...........
9 ...........
What I need is to update TableB by setting the age for all users
from England to be 20
and from France to be 50
and so on...
update tableB
set age = (select tableA.value from tableA where tableA.StateID=TableB.id)
I like this form below:
update b set
age = a.value
from tableB b
join tableA a on a.id = b.stateId
because you can write it this way (at last in SQL Server Management Studio):
update b set
age = a.value
--select b.age, a.value, b.*, a.*
from tableB b
join tableA a on a.id = b.stateId
then highlight the part from select ... to the end of query and execute it (F5) to check what you are going to change (value before and after).

Transposing rows to columns using self join

I have a table named category with values as below,
CategoryId | Value | Flag
1 25 a
2 26 a
3 27 a
1 28 m2 23 m
1 36 p2 33 p
Now I want to transpose the rows present in this table to columns based on the flag, something like
CategoryId | aValue | mValue | PValue
1 25 28 36
2 26 23 33
3 27 null null
I am trying to join based on the category id but I am just getting the matched records (inner join) in my resultset even if I use left outer join in my query.
My query:
SELECT
A.CategoryId,
A.Value AS actual,
B.Value AS projected,
C.Value AS Manual
FROM ((a AS A left JOIN b AS B ON A.categoryid=B.categoryid)
left JOIN c AS C ON A.categoryid=C.categoryid)
WHERE (((A.flag)="a") and ((B.flag)="p") and ((C.flag) ="m"))
I am getting the proper results if I have the data in 3 different tables.
I just want to check what would be the best way to transpose a rows to column when using self join...
Thanks,
Barani
Try this:
SELECT CategoryId,
MIN(SWITCH(YourTable.Flag = 'a',Value)) AS aValue,
MIN(SWITCH(YourTable.Flag = 'm',Value)) AS mValue,
MIN(SWITCH(YourTable.Flag = 'p',Value)) AS pValue
FROM YourTable
GROUP BY CategoryId