SQL Server 2012 multiple joins technique - sql

I have appended a series of columns (11 of them) to the end my data that each act as a flag.
Here is a sample of these categories:
(Notice that multiple flags can appear for a single row!)
cat2 cat3 cat4 cat5 cat6 cat7 cat8 cat9 cat10 cat11 cat12
NULL 1 NULL NULL 2 NULL NULL 1 NULL NULL NULL
NULL NULL NULL NULL NULL NULL 2 NULL NULL NULL NULL
NULL NULL NULL 1 1 NULL NULL NULL NULL NULL NULL
NULL 1 1 NULL NULL NULL NULL NULL NULL NULL NULL
3 NULL NULL NULL NULL NULL 2 NULL NULL NULL NULL
I have a separate table that pairs each flag with a description string.
ref_id category_position description
------------------------------------------------
1 2 string description 1
2 2 string description 2
3 2 string description 3
1 3 string description 4
1 4 string description 5
1 5 string description 6
1 6 string description 7
2 6 string description 8
1 7 string description 9
1 8 string description 10
2 8 string description 11
1 9 string description 12
1 10 string description 13
1 11 string description 14
1 12 string description 15
I want to somehow join my string description against every category that is not null, so that my categories are 'human readable' and defined.
Here is a possible outcome that would be acceptable to me, based on the first row of sample data (including the header):
cat3 [join description] cat6 [join description] cat9 [join description]
1 string description 4 2 string description 8 1 string description 12
Trouble is - I don't know how to do this multi-part join. I don't want to join 12 times as this seems sloppy and perhaps won't work for the millions of rows I'm operating on.

Here's the function alternative... which isn't going to be faster than doing the joins but is useful in limited use.
create function dbo.returnDesc (#ref_id int)
returns varchar (256)
as
begin
declare #return varchar(256)
set #return = (select [description] from yourTable where ref_id = #ref_id)
return #return
end
Then in use....
select
....
dbo.returnDesc(cat2),
dbo.returnDesc(cat3),
dbo.returnDesc(cat4),
....
from
YourMainTable

Related

SQL to fetch data using column values from one table as columns of another table

I have these two tables:
Org_Extra_Attr
org_id attr_name attr_path
1 desk_name str1
1 citizen bool1
2 perm_user bool1
3 skype_id str1
3 twitter str2
User_Attr_Values
org_id user_id str1 str2 str3 str4 bool1 bool2 bool3 bool4
1 1 b1d07 null null null 1 null null null
1 2 b2d01 null null null 0 null null null
2 3 null null null null 1 null null null
2 4 null null null null 1 null null null
3 5 sam_sky sam_twt null null null null null null
3 6 tom_sky tom_twt null null null null null null
So, the thing here is each org.can define max.of 4 extra attributes of type String and Boolean each, the Org_Extra_Attr table is like meta-data. For example org_id 1 has defined desk_name which will be str1's value for its users, whereas org_id 3 has skype_id which will be str1's value for its users.
This might be a bad design, but for now, I need to get users attribute names and values for a given org_id. Like for org_id = 1, I need a SQL query result(not a third table) like below:
user_id attr_name val
1 desk_name b1d07
1 citizen 1
2 desk_name b2d01
2 citizen 0
For org_id = 3
user_id attr_name val
5 skype_id sam_sky
5 twitter sam_twt
6 skype_id tom_sky
6 twitter tom_twt
Something like this
select
t2.user_id,
t1.attr_name,
CASE
WHEN t1.attr_path='str1' then t2.str1
WHEN t1.attr_path='str2' then t2.str2
WHEN t1.attr_path='str3' then t2.str3
WHEN t1.attr_path='str4' then t2.str4
WHEN t1.attr_path='bool1' then t2.bool1
WHEN t1.attr_path='bool2' then t2.bool2
WHEN t1.attr_path='bool3' then t2.bool3
WHEN t1.attr_path='bool4' then t2.bool4
END attr_value
FROM org_Extra_attr t1 inner join User_Attr_Values t2
on t1.org_id = t2.org_id
where t1.org_id=1
This is not an answer, but too long for a comment
That is a bad data model. You should not store column names in your tables.
What you could have instead is:
Org_Attr (PK = org_id + attr_no)
org_id attr_no attr_name type
1 1 desk_name STRING
1 2 citizen BOOL
2 1 perm_user BOOL
3 1 skype_id STRING
3 2 twitter STRING
Org_Attr_User (PK = org_id + attr_no + user_id)
org_id attr_no user_id value
1 1 1 b1d07
1 1 2 b2d01
1 2 1 1
1 2 2 0
2 1 3 1
2 1 4 1
3 1 5 sam_sky
3 1 6 tom_sky
3 2 5 sam_twt
3 2 6 tom_twt
With such a model data integrity would be guaranteed and querying, too, would be simple:
select oau.user_id, oa.attr_name, oau.value
from Org_Attr oa
join Org_Attr_User oau using (org_id, attr_no)
where org_id = 1;

Compare the column values where there are null and not null values

I want to compare the values from a table where there are null and not null values for the same ID ( If not null then I want minimum of two not null values). IF all the values are null for the given ID, I want the values to be displayed as null for the ID.
Input
ID Amount
1 Null
1 Null
1 Null
1 500
1 600
1 700
2 Null
2 Null
2 Null
2 Null
2 Null
3 Null
3 Null
3 300
3 600
3 200
Expected output
ID Amount
1 500 (min Not null value)
2 Null
3 200 (Min Not null value)
Simple grouping will do the trick:
select t.id, min(t.amount)
from table t
group by t.id

SQL merge and sum multiple rows into one

Essentially I have a SQL table that looks like this;
Name Week 1 Week 2 Week 3 Week 4 Week 5
James NULL 5 NULL NULL NULL
James 10 NULL NULL NULL NULL
James NULL NULL NULL 5 NULL
James NULL NULL NULL 20 NULL
Tom NULL NULL 5 NULL NULL
Tom NULL 10 NULL NULL NULL
Tom 25 NULL NULL NULL NULL
Tom NULL NULL NULL 5 NULL
Tom NULL NULL NULL 5 NULL
And I would want to combine together the rows (while also summing the values) to get something more like this;
Name Week 1 Week 2 Week 3 Week 4 Week 5
James 10 5 20 25 NULL
Tom 25 10 5 10 NULL
But I can't think of a good way of doing so. My data has quite the number of columns and rows so I'm looking for something which ideally doesn't require listing out all the individual column or row names.
Thanks
Just Sum the Rows and Group by name
select
Name
, Week1 = sum(Week 1)
, Week2 = sum(Week 2)
, Week3 = sum(Week 3)
, Week4 = sum(Week 4)
, Week5 = sum(Week 5)
from Table
group by Name

SQL nested loops

I have a problem, I have added a column to one of my database tables and now i need to populate this column with data.
Here are the tables:
Table QUESTIONNAIRE_QUESTIONS
with columns:
ID,
QUESTION_NUMBER,
PARENT_QUESTION_ID,
PARENT_QUESTIONNAIRE_ID,
QUESTION_CODE
Table QUESTIONNAIRE
with columns:
ID,
INTRODUCTION
What I first need to do is to find all unique QUESTIONNAIRE.ID and for each of those I need to find all QUESTIONNAIRE_QUESTIONS.ID that have this id as PARENT_QUESTIONNAIRE_ID and set the QUESTION_CODE as QUESTION_CODE=QUESTION_NUMBER*100.
Then, before moving on to the next QUESTIONNAIRE_ID i need to find all QUESTIONNAIRE_QUESTIONS.ID that have the current QUESTIONNAIRE_QUESTIONS.ID as PARENT_QUESTION_ID and set the QUESTION_CODE as
QUESTION_CODE=(parents question_code)+'.'+QUESTION_CODE.QUESTION_NUMBER*100.
How to perform this, complicated, nested loop? Seems like I have to use several loops?
Sample Data:
QUESTIONNAIRES
ID
1869359
1876176
QUESTIONNAIRE_QUESTIONS
ID QUESTION_NUMBER PARENT_QUESTIONNAIRE_ID PARENT_QUESTION_ID QUESTION_CODE
1869360 1 1869359 null null
1869362 2 1869359 null null
1869364 3 1869359 null null
1869367 1 null 1869364 null
1869369 1 1876176 null null
1869371 2 1876176 null null
1869372 3 1876176 null null
1869374 4 1876176 null null
1869377 1 null 1869372 null
And after i want it to look like this:
QUESTIONNAIRE_QUESTIONS
ID QUESTION_NUMBER PARENT_QUESTIONNAIRE_ID PARENT_QUESTION_ID QUESTION_CODE
1869360 1 1869359 null 100
1869362 2 1869359 null 200
1869364 3 1869359 null 300
1869367 1 null 1869364 300.100
1869368 1 null 1869367 300.100.100
1869369 2 null 1869367 300.100.200
1869370 1 1876176 null 100
1869371 2 1876176 null 200
1869372 3 1876176 null 300
1869374 4 1876176 null 400
1869377 1 null 1869371 200.100
Note that it can be more levels of "child questions"
Thanks!
UPDATE QUESTIONNAIRE_QUESTIONS
SET QUESTION_CODE = (QUESTION_NUMBER * 100)
WHERE QUESTIONNAIRE_QUESTIONS.ID IN (SELECT DISTINCT QUESTIONNAIRE.ID
FROM QUESTIONNAIRE, QUESTIONNAIRE_QUESTIONS
WHERE QUESTIONNAIRE_QUESTIONS.ID = PARENT_QUESTION_ID)
Not so sure about the 2nd question. Is that a typo?QUESTION_CODE.QUESTION_NUMBER*100

lookup tables with temporary fields?

I have a query that produces the following results:
table1:
degree_code occupation_code degree_completions degree_level
1.0000 20-2021 10 1
1.0000 20-2022 10 1
1.1051 52-2095 2 3
1.1051 52-2095 41 2
1.5010 15-1100 2 3
I have another small, lookup table that relates degree_level to custom categories that I need to use:
table2
degree_level degree_level_recode
1 AADEGREE
2 AADEGREE
3 BACHDEGREE
I would like to build the output of of the first query to report the following format:
degree_code occupation_code degree_completions degree_level AADEGREE BACHDEGREE
1.0000 20-2021 10 1 10 0
1.0000 20-2022 10 1 10 0
1.1051 52-2095 2 3 3 0
1.1051 52-2095 41 2 0 41
1.5010 15-1100 2 3 2 1
Basically, create new temporary recode fields in the original query that report the degree_completions underneath them when they match the degree_level_recode, input 0 if no match. This is highly simplified; I will be performing operations on the recode fields against other fields in each element in the query.
I've shown the degree_completions field for reference, but I'd leave it out in the final query for obvious redundancy reasons.
I'm thinking I need to use a CASE statement or something similar for comparison checking, but I'm new to SQL.
EDIT:
In reference to Cha's answer below, take a revised table1 output (after mapping the recode):
degree_code degree_level degree_completions degree_level_recode
01.0601 2 11 LESSCOLL
01.0601 3 22 AADEGR
01.0605 2 3 LESSCOLL
Consider this code (table2 is referenced above the edit):
SELECT degree_code
,degree_level
,[LESSCOL] AS LESSCOL
,[AADEGR] AS AADEGR
,[BACHDEGR] AS BACHDEGR
,[MADEGR] AS MADEGR
,[DOCDEGR] AS DOCDEGR
FROM
(
SELECT degree_code
,table1.degree_level
,degree_level_recode
,degree_code
FROM table1
,table2
WHERE table1.degree_level = table2.degree_code
) AS p
PIVOT
(
SUM (degree_completions)
FOR degree_level_recode IN ([LESSCOL], [AADEGR], . . .)
) AS pvt
Which produces these results:
degree_code degree_level LESSCOL AADEGR BACHDEGR MADEGR DOCDEG
01.0601 2 NULL NULL NULL NULL NULL
01.0601 3 NULL 22 NULL NULL NULL
01.0505 2 NULL NULL NULL NULL NULL
I'm trying to get to:
degree_code degree_level LESSCOL AADEGR BACHDEGR MADEGR DOCDEG
01.0601 2 11 NULL NULL NULL NULL
01.0601 3 NULL 22 NULL NULL NULL
01.0505 2 3 NULL NULL NULL NULL
Additionally, replace NULL with 0.
This is what you are after (assumptions: your first table is called #temp1, your second table is called #temp2):
SELECT *
FROM
#temp1,
(SELECT degree_level, [AADEGREE] as col1, [BACHDEGREE] as col2
FROM
(SELECT degree_completions, #temp1.degree_level, degree_level_recode
FROM #temp1, #temp2 WHERE #temp1.degree_level = #temp2.degree_level) AS p
PIVOT
(
SUM (degree_completions)
FOR degree_level_recode IN
([AADEGREE], [BACHDEGREE])
) AS pvt
) as V
WHERE #temp1.degree_level = V.degree_level
ORDER BY 1