Need help on SQL join - sql

I have 2 tables as below:
select 1 as id,
'A' as place
into #places
UNION
select 2 as id,
'B' as place
UNION
select 3 as id,
'C' as place
UNION
select 4 as id,
'D' as place
select 'x' as name,
2 as start,
3 as endd
into #travel
UNION
select 'y' as name,
4 as start,
1 as endd
UNION
select 'z' as name,
1 as start,
3 as endd
select * from #places
select * from #travel
------------------------------
Now I want to get name/start place/end place using joins?

SELECT
t.name,
p1.place as start_place,
p2.place as end_place
FROM
travel t
JOIN places p1 on t.start = p1.id
JOIN places p2 on t.endd = p2.id

select #travel.*, pstart.place as start, pend.place as end
from #travel inner join #places as pstart on pstart.id = #travel.start
inner join #places as pend on pend.id = #travel.end

Related

Get all parent rows and each row followed by their child's rows

I've two tables one of them called
Main-Level
another one called
Sub-level
Sub-level has a foreign key from the Main level (the relation between them Main-Level has one or Many Sub-levels )
what I want is to create a query to show the Main-level row followed by all Sub-level rows such as below screen-shot either by native SQL query or LINQ.
Update:
I used below but the problem is it the result such as Full OUTer JOIN !
select * from Sublevel
right join Mainlevel
on Sublevel.mainlevelID=Mainlevel.id
order by coalesce(Sublevel.mainlevelID, Mainlevel.id),
(case when Sublevel.mainlevelID is null then 1 else 0 end),Mainlevel.id;
Update 2:
Also, I tried below query but with no luck :
SELECT
s.name,
s.Id,
CASE WHEN s.is_child = 1 THEN s.parentID END AS parent_id,
m.name
FROM
Mainlevel m
INNER JOIN (
SELECT id, name, parentID, 1 AS is_child
FROM Sublevel
UNION ALL
SELECT id, name,Null, 0 AS is_child
FROM Mainlevel
) s on m.id = s.mainlevelID
ORDER BY m.id,is_child, s.mainlevelID
My problem in simple language is How to make the child rows appeared below parent row
The overall plan is to have parent join (parent + child) order by (parent ID, child ID)
SELECT
c.level_id,
c.level_name,
c.level_code,
CASE WHEN c.is_child = 1 THEN c.parent_id END AS parent_id,
FROM
mainLevel p
INNER JOIN (
SELECT level_id, level_name, level_code, parent_id, 1 AS is_child
FROM subLevel
UNION ALL
SELECT level_id, level_name, level_code, level_id, 0 AS is_child
FROM mainLevel
) c on p.level_id = c.parent_id
ORDER BY p.level_id, is_child, c.level_id
Additional version to adopt to the newly clarified column availability
SELECT
w.name,
w.id,
CASE WHEN w.is_child = 1 THEN w.mid END AS parent_id
FROM
Mainlevel m
INNER JOIN (
SELECT id, name, parentID AS mid, 1 AS is_child
FROM Sublevel
UNION ALL
SELECT id, name, id AS mid, 0 AS is_child
FROM Mainlevel
) w on m.id = w.mid
ORDER BY m.id, is_child, w.id
You can use order by:
order by coalesce(parentid, id),
(case when parentid is null then 1 else 0 end),
id

SQL join and Bring in 1 column into 2 columns

I have two tables shown as above. I want to create a select statement that would have the following result:
Basically, I want to join on 'Model' and 'Num' columns and bring 'Val' vales but break it into two columns based on 'Ver'.
SELECT 'a' as Model ,'1' as Num ,'v1' as Ver ,'9' as val INTO #RefTbl UNION ALL
SELECT 'a','2','v1','10' UNION ALL
SELECT 'a','3','v1','11' UNION ALL
SELECT 'a','1','v2','5' UNION ALL
SELECT 'a','2','v2','6' UNION ALL
SELECT 'a','3','v2','7' UNION ALL
SELECT 'b','1','v1','20' UNION ALL
SELECT 'b','1','v2','21' UNION ALL
SELECT 'b','2','v1','25' UNION ALL
SELECT 'b','2','v2','26'
SELECT '519' as ID,'a' as Model,'1' as Num INTO #OrderTbl UNION ALL
SELECT '5616','a','3' UNION ALL
SELECT '871','b','1'
-- failed attempt
SELECT o.*, '' as v1_val, '' as v2_val FROM #OrderTbl as o left join #RefTbl as r on o.Model = r.Model and o.Num = r.Num
You can join and do conditional aggregation:
select
d.ID,
d.Model,
d.Num,
max(case when r.Ver = 'val1' then Val end) V1_Val,
max(case when r.Ver = 'val2' then Val end) V2_Val
from DataTbl d
inner join ReferenceTbl r
on r.Model = d.Model
and r.Num = d.Num
group by
d.ID,
d.Model,
d.Num
Alternatively, you can join twice - depending on your dataset, this might (or might not) perform better:
select
d.ID,
d.Model,
d.Num,
r1.Val V1_Val,
r2.Val V2_Val
from DataTbl d
left join ReferenceTbl r1
on r1.Model = d.Model
and r1.Num = d.Num
and r1.Ver = 'val1'
left join ReferenceTbl r2
on r2.Model = d.Model
and r2.Num = d.Num
and r2.Ver = 'val2'
Case + Group by works on most db system which is nice.
Alternative answer using SQL Server PIVOT (for reference)
WITH RefTbl AS (
SELECT 'a' as Model ,'1' as Num ,'v1' as Ver ,'9' as val UNION ALL
SELECT 'a','2','v1','10' UNION ALL
SELECT 'a','3','v1','11' UNION ALL
SELECT 'a','1','v2','5' UNION ALL
SELECT 'a','2','v2','6' UNION ALL
SELECT 'a','3','v2','7' UNION ALL
SELECT 'b','1','v1','20' UNION ALL
SELECT 'b','1','v2','21' UNION ALL
SELECT 'b','2','v1','25' UNION ALL
SELECT 'b','2','v2','26'),
OrderTbl AS (
SELECT '519' as ID,'a' as Model,'1' as Num UNION ALL
SELECT '5616','a','3' UNION ALL
SELECT '871','b','1'
)
SELECT Id, Model, Num AS Model, [v1] AS v1_Val, [v2] as v2_Val
FROM
(SELECT o.id, r.Model, r.Num, r.val, r.ver from OrderTbl as o
left join RefTbl as r on o.Model = r.Model and o.Num = r.Num) AS SourceTable
PIVOT
(MAX(val) FOR ver IN ([v1], [v2])) AS PivotTable;
Id Model Model v1_Val v2_Val
519 a 1 9 5
5616 a 3 11 7
871 b 1 20 21

Many to Many with multiple Ands

I am trying a simple (or not) query to get Users that exist in 2 Departments.
Struct:
User
ID
Name
UserDepartment
ID
IDUser
IDDepartment
Department
ID
Name
So i want users from DepartmentA and DepartmentB (
Is imposible to do:
Select * from User as US
left join UserDepartment as DP on User.ID = UserDepartment.IDUser
where DP.IDDepartment = 1 and DP.IDDepartment = 2
Zero results...
An query to resolve this is sothing like:
select * from UserDepartment
where IDDepartment in (1,2)
group by IDUser
having COUNT(*)=2
But is this the only solution? there are other easy queries out there?
To get all users that belong in both 1 and 2 departments:
SELECT *
FROM User
WHERE User.ID IN (SELECT UserID FROM UserDepartment WHERE IDDepartment = 1)
AND User.ID IN (SELECT UserID FROM UserDepartment WHERE IDDepartment = 2)
The results are essentially the same as the latter query you have, except it specifically looks for people who are in both "1" and "2", rather than anybody who has 2 or more department records that belong to "1" or "2" (doesn't include people with two "1" records but no "2" records).
If there's information from the userdepartment table you want included in the results, just change it to:
SELECT *
FROM User US
INNER JOIN (SELECT * FROM UserDepartment WHERE IDDepartment IN(1,2)) DP ON US.ID = DP.UserID
WHERE User.ID IN (SELECT UserID FROM UserDepartment WHERE IDDepartment = 1)
AND User.ID IN (SELECT UserID FROM UserDepartment WHERE IDDepartment = 2)
This seems like a job for INTERSECT. You can get the list of user id's you want by doing something like:
SELECT IDUser FROM UserDepartment WHERE IDDepartment = 1
INTERSECT
SELECT IDUser FROM UserDepartment WHERE IDDepartment = 2
/*** If only users for dept 1 and 2 need to be shown the use this query ****/
Select * from #User u
inner join
(
Select d1.UserID from #UserDepartment d1
where d1.Department = 1
intersect
Select d2.UserID from #UserDepartment d2
where d2.Department = 2
except
Select d2.UserID from #UserDepartment d2
where d2.Department not in (1,2)
)t on u.ID = t.UserID
/***If the users that belong to dept 1 and 2 and can exist in
other depts then use this one**/
Select * from #User u
inner join
(
Select d1.UserID from #UserDepartment d1
where d1.Department = 1
intersect
Select d2.UserID from #UserDepartment d2
where d2.Department = 2
)t on u.ID = t.UserID
/**To test use the following commented code**/
/*Select * into #User from
(
Select 1 as ID, 'A' as Name
union
Select 2,'B'
union
Select 3,'C'
union
Select 4,'D'
union
Select 5,'E'
union
Select 6,'F'
union
Select 7,'G'
union
Select 8,'H'
union
Select 9,'I'
union
Select 10,'G'
)t
Select * into #Department from
(
Select 1 as ID, 'D1' as Name
union
Select 2,'D2'
union
Select 3,'D3'
union
Select 4,'D4'
)t2
Select * into #UserDepartment from
(
Select 1 AS ID ,1 AS UserID ,1 AS Department
union
Select 2,1,2
union
Select 3,1,3
union
Select 4,2,1
union
Select 5,3,2
union
Select 6,4,1
union
Select 7,4,2
)t3
*/

How to get only one value when you are getting multiple values against key in SQL

I have a SQL query. Below is the query
select
ID,
replace(replace(replace(replace([Name],',',''),'"',''),':',''),'?','') [Name] ,
replace(replace([Description],',',''),'"','') [Description],
[GUID],
Bussinesskey
from course
where COURSESTATUS = 'Published' and RETIREDTF = 0
and
bussinesskey in
(
...
)
and id in (
select c.id from course c
inner join COURSE_CUSTOMERENTITLEMENT cce on cce.COURSE_ID = c.ID
inner join CUSTOMERENTITLEMENT ce on ce.id = cce.CUSTOMERENTITLEMENT_ID
where
ce.ENROLLMENTTYPE = 'Course'
and ce.customer_id = 23753
and c.COURSESTATUS = 'Published' and c.RETIREDTF = 0
UNION
select c.id from course c
inner join COURSE_COURSEGROUP cg on cg.course_id = c.id
inner join COURSEGROUP_CUSTOMERENTITLEMENT cgce on cgce.COURSEGROUP_ID = cg.COURSEGROUP_ID
inner join CUSTOMERENTITLEMENT ce on ce.id = cgce.CUSTOMERENTITLEMENT_ID
where
ce.ENROLLMENTTYPE = 'CourseGroup'
and ce.customer_id = 23753
and c.COURSESTATUS = 'Published' and c.RETIREDTF = 0
)
order by name, id asc
When this query runs then I get the output like the following snapshot
You can see in the screen shot that I am getting 8 names of same type(Contracts). The last id of Contracts is 780697 which is the latest record that is added to database. Now i want that when my query runs then it gets only the latest record. Means instead of showing 8 name of Contarcts. Its only the show the latest one for each course name. Means for Contracts only record with ID 780697 is shown. If other courses has the same result then there latest Id record is shown only. How can I achieve this ?
Thanks
You can try following for achieving latest ID:-
select MAX(ID),
replace(replace(replace(replace([Name],',',''),'"',''),':',''),'?','') [Name] ,
replace(replace([Description],',',''),'"','') [Description],
[GUID],
Bussinesskey
from course
where COURSESTATUS = 'Published' and RETIREDTF = 0
and
bussinesskey in
(
...
)
and id in (
select c.id from course c
inner join COURSE_CUSTOMERENTITLEMENT cce on cce.COURSE_ID = c.ID
inner join CUSTOMERENTITLEMENT ce on ce.id = cce.CUSTOMERENTITLEMENT_ID
where
ce.ENROLLMENTTYPE = 'Course'
and ce.customer_id = 23753
and c.COURSESTATUS = 'Published' and c.RETIREDTF = 0
UNION
select c.id from course c
inner join COURSE_COURSEGROUP cg on cg.course_id = c.id
inner join COURSEGROUP_CUSTOMERENTITLEMENT cgce on cgce.COURSEGROUP_ID = cg.COURSEGROUP_ID
inner join CUSTOMERENTITLEMENT ce on ce.id = cgce.CUSTOMERENTITLEMENT_ID
where
ce.ENROLLMENTTYPE = 'CourseGroup'
and ce.customer_id = 23753
and c.COURSESTATUS = 'Published' and c.RETIREDTF = 0
)
group by [Name], [Description], [GUID], Bussinesskey
order by name, id asc
Here how I did this. I don't know how efficient this is but it's giving me what I am exactly wanting
select ID, [Name], [Description], [GUID], Bussinesskey from (
select row_number() over (partition by [Name] order by id desc) as row, t1.* from (
select
ID,
replace(replace(replace(replace([Name],',',''),'"',''),':',''),'?','') [Name] ,
replace(replace([Description],',',''),'"','') [Description],
[GUID],
Bussinesskey
from course
where COURSESTATUS = 'Published' and RETIREDTF = 0
and bussinesskey in (
'PSTOAS0314001',
...
'RECEAL0510019'
)
and id in (
select c.id from course c
inner join COURSE_CUSTOMERENTITLEMENT cce on cce.COURSE_ID = c.ID
inner join CUSTOMERENTITLEMENT ce on ce.id = cce.CUSTOMERENTITLEMENT_ID
where ce.ENROLLMENTTYPE = 'Course'
and ce.customer_id = 23753
and c.COURSESTATUS = 'Published' and c.RETIREDTF = 0
UNION
select c.id from course c
inner join COURSE_COURSEGROUP cg on cg.course_id = c.id
inner join COURSEGROUP_CUSTOMERENTITLEMENT cgce on cgce.COURSEGROUP_ID = cg.COURSEGROUP_ID
inner join CUSTOMERENTITLEMENT ce on ce.id = cgce.CUSTOMERENTITLEMENT_ID
where ce.ENROLLMENTTYPE = 'CourseGroup'
and ce.customer_id = 23753
and c.COURSESTATUS = 'Published' and c.RETIREDTF = 0
)
)t1
) t
where t.row=1
order by t.name, t.id asc
Thanks
;with Course as
(
Select 50000 ID, 'Contracts' Name, '<BLURB>' [Description], '<GUID>' GUID, 'ARB1' BusinessKey
UNION
Select 60000 ID, 'Contracts' Name, '<BLURB>' [Description], '<GUID>' GUID, 'ARB2' BusinessKey
UNION
Select 70000 ID, 'Contracts' Name, '<BLURB>' [Description], '<GUID>' GUID, 'ARB3' BusinessKey
UNION
Select 80000 ID, 'Contracts' Name, '<BLURB>' [Description], '<GUID>' GUID, 'ARB4' BusinessKey
UNION
Select 90000 ID, 'Contracts' Name, '<BLURB>' [Description], '<GUID>' GUID, 'ARB5' BusinessKey
UNION
Select 40000 ID, 'NOT Contracts' Name, '<BLURB>' [Description], '<GUID>' GUID, 'ARB1' BusinessKey
),
Course_Group AS
(
Select 50000 Course_ID, 1 COURSEGROUP_ID
UNION
Select 60000 Course_ID, 1 COURSEGROUP_ID
UNION
Select 70000 Course_ID, 1 COURSEGROUP_ID
UNION
Select 80000 Course_ID, 1 COURSEGROUP_ID
UNION
Select 90000 Course_ID, 2 COURSEGROUP_ID
UNION
Select 40000 Course_ID, 1 COURSEGROUP_ID
),
CourseGroup_CustomerEntitlement AS
(
Select 1 COURSEGROUP_ID, 1 CUSTOMERENTITLEMENT_ID
--UNION
--Select 2 COURSEGROUP_ID, 2 CUSTOMERENTITLEMENT_ID
--UNION
--Select 2 COURSEGROUP_ID, 4 CUSTOMERENTITLEMENT_ID
),
Course_CustomerEntitlement AS
(
Select 50000 Course_ID, 3 CUSTOMERENTITLEMENT_ID
UNION
Select 60000 Course_ID, 3 CUSTOMERENTITLEMENT_ID
UNION
Select 90000 Course_ID, 3 CUSTOMERENTITLEMENT_ID
UNION
Select 40000 Course_ID, 4 CUSTOMERENTITLEMENT_ID
),
CustomerEntitlement AS
(
Select 1 ID, 23753 Customer_ID, 'CourseGroup' ENROLLMENTTYPE
UNION
Select 2 ID, 7 Customer_ID, 'NOT COURSE GROUP' ENROLLMENTTYPE
UNION
Select 3 ID, 23753 Customer_ID, 'Course' ENROLLMENTTYPE
UNION
Select 4 ID, 7 Customer_ID, 'NOT COURSE' ENROLLMENTTYPE
),
CTE_base_data as (
SELECT
C.ID,
replace(replace(replace(replace(C.[Name],',',''),'"',''),':',''),'?','') [Name] ,
replace(replace(C.[Description],',',''),'"','') [Description],
C.[GUID],
C.Businesskey
FROM Course C
JOIN Course_Group CG ON CG.Course_ID = C.ID
JOIN CourseGroup_CustomerEntitlement CG_CE ON CG_CE.COURSEGROUP_ID = CG.COURSEGROUP_ID
JOIN CustomerEntitlement CE_GROUP ON CE_GROUP.ID = CG_CE.CUSTOMERENTITLEMENT_ID
AND CE_GROUP.ENROLLMENTTYPE = 'CourseGroup'
WHERE
CE_GROUP.Customer_ID = 23753
UNION
SELECT
C.ID,
replace(replace(replace(replace([Name],',',''),'"',''),':',''),'?','') [Name] ,
replace(replace([Description],',',''),'"','') [Description],
[GUID],
Businesskey
FROM Course c
JOIN Course_CustomerEntitlement CCE ON CCE.Course_ID = C.ID
JOIN CustomerEntitlement CE_COURSE ON CE_COURSE.ID = CCE.CUSTOMERENTITLEMENT_ID
AND CE_COURSE.ENROLLMENTTYPE = 'COURSE'
WHERE
CE_COURSE.Customer_ID = 23753
--and COURSESTATUS = 'Published'
--and RETIREDTF = 0
--and businesskey in
-- (
-- ...
-- )
),
CTE_max_data as (
Select name, max(ID) ID
from CTE_base_data
group by name
)
Select Data.*
from CTE_base_data Data
JOIN CTE_max_data Filter
ON Data.ID = Filter.ID
AND Data.Name = Filter.Name
order by name, id asc
This yields:
ID Name Description GUID Businesskey
90000 Contracts ARB5
40000 NOT Contracts ARB1
Please advise where my data assumptions fall flat.

Get distinct result

I have the following tables
Product --stored for productid
ProductRelation -- storing linked product id's
DECLARE #Product table(ProductID int)
DECLARE #ProductRelation TABLE (FirstProductID int,SecondProductID int)
INSERT INTO #Product
SELECT 1
UNION ALL
SELECT 2
UNION ALL
SELECT 3
UNION ALL
SELECT 4
UNION ALL
SELECT 5
UNION ALL
SELECT 6
UNION ALL
SELECT 7
UNION ALL
SELECT 8
UNION ALL
SELECT 9
UNION ALL
SELECT 10
--SELECT * FROM #Product
INSERT INTO #ProductRelation
SELECT 1,2
UNION ALL
SELECT 3,5
UNION ALL
SELECT 2,6
UNION ALL
SELECT 1,4
UNION ALL
SELECT 1,4
--SELECT * FROM #ProductRelation
SELECT ProductID,'Not Linked' AS 'Relation' FROM #Product
UNION
SELECT FirstProductID,'Linked' from #ProductRelation
UNION
SELECT SecondProductID ,'Linked' FROM #ProductRelation
Above query results repeating ProductID
I wanted to select distinct ProductID...if there is relation between product id then it should display the ProductID with 'Linked'
If no relation then ProductID with 'Not Linked'
I want the expected result like this
ProductID Relation
1 Linked
2 Linked
3 Linked
4 Linked
5 Linked
6 Linked
7 Not Linked
8 Not Linked
9 Not Linked
10 Not Linked
Try this:
SELECT
P.ProductID,
CASE WHEN COUNT(R.FirstProductID) > 0
THEN 'Linked'
ELSE 'Not Linked'
END Relation
FROM Product P
LEFT JOIN ProductRelation R
ON P.ProductID = R.FirstProductID
OR P.ProductID = R.SecondProductID
GROUP BY P.ProductID
well... I love this opportunity to use some unpivot tricks!
select P.ProductID
,isnull(L.relation,'Not Linked') as relation
from #Product P
left outer join (select U.ProductID, cast('Linked' as varchar(max)) as relation
from #ProductRelation
unpivot (ProductID for prod in (FirstProductID,SecondProductID))U
group by U.ProductID
)L
on L.ProductID = P.ProductID
You can use a left join combined with a CASE WHEN in SQL Server
SELECT DISTINCT
ProductID,
CASE WHEN #ProductRelation.FirstProductId IS NULL THEN 'Not Linked' ELSE 'Linked' END [Status]
FROM #Product
LEFT JOIN #ProductRelation ON #Product.ProductID = #ProductRelation.FirstProductId
RIGHT JOIN #ProductRelation ON #Product.ProductID = #ProductRelation.SecondProductId