Recursive CTE with alternating tables - sql

I've created a SQL fiddle here.
Basically, I have 3 tables BaseTable, Files, and a LinkingTable.
The Files table has 3 columns: PK, BaseTableId, RecursiveId (ChildId).
What I want to do is find all the children given a BaseTableId (i.e., ParentId).
The tricky part is that the way the children are found works like this:
Take ParentId(BaseTable.BaseTableId) 1 and use that to look up a FileId in the Files table, then use that FileId to look for a ChildId(LinkingTable.RecursiveId) in the LinkingTable, if that record exists then use the RecursiveId in the LinkingTable to look for the next FileId in the Files table and so on.
This is my CTE so far:
with CTE as
(
select lt.FileId, lt.RecursiveId, 0 as [level],
bt.BaseTableId
from BaseTable bt
join Files f
on bt.BaseTableId = f.BaseTableId
join LinkingTable lt
on f.FileId = lt.FileId
where bt.BaseTableId = #Id
UNION ALL
select rlt.FileId, rlt.RecursiveId, [level] + 1 as [level],
CTE.BaseTableId
from CTE --??? and this is where I get lost
...
)
A correct output for BaseTableId = 1, should be:
FileId|RecursiveId|level|BaseTableId
1 1 0 1
3 2 1 1
4 3 2 1
Table Relationship

Here is a recursive example that I believe meets your criteria. I added a ParentId to the result set, which will be NULL for the root/base file, since it does not have a parent.
declare #BaseTableId int;
set #BaseTableId = 1;
; WITH cteRecursive as (
--anchor/root parent file
SELECT null as ParentFileId
, f.FileId as ChildFileID
, lt.RecursiveId
, 0 as [level]
, bt.BaseTableId
FROM BaseTable bt
INNER JOIN Files f
on bt.BaseTableId = f.BaseTableId
INNER JOIN LinkingTable lt
on f.FileId = lt.FileId
WHERE bt.BaseTableId = #BaseTableId
UNION ALL
SELECT cte.ChildFileID as ParentFileID
, f.FileId as ChildFileID
, lt.RecursiveId
, cte.level + 1 as [level]
, cte.BaseTableId
FROM cteRecursive cte
INNER JOIN Files f on cte.RecursiveId = f.RecursiveId
INNER JOIN LinkingTable lt ON lt.FileId = f.FileId
)
SELECT *
FROM cteRecursive
;
Results for #BaseTableID = 1:
ParentFileId ChildFileID RecursiveId level BaseTableId
------------ ----------- ----------- ----------- -----------
NULL 1 1 0 1
1 3 2 1 1
3 4 3 2 1
Results for #BaseTableID = 2:
ParentFileId ChildFileID RecursiveId level BaseTableId
------------ ----------- ----------- ----------- -----------
NULL 2 1 0 2
NULL 2 4 0 2
2 6 5 1 2
6 7 6 2 2
2 3 2 1 2
3 4 3 2 2

Related

Query to get translation for each languages

Please help me to create query. I have table with languages like
Id Code
---------
1 EN
2 DE
3 RU
and table with translations
Id Code LanguageId Value
------------------------------------------
1 1 1 EnglishTranslation
2 1 3 RussianTranslation
3 2 1 EnglishTranslation
4 2 2 DeutschTranslation
5 3 1 EnglishTranslation
I'm trying to get this result
Id Code LanguageId Value
------------------------------------------
1 1 1 EnglishTranslation
1 1 2 NULL
2 1 3 RussianTranslation
3 2 1 EnglishTranslation
4 2 2 DeutschTranslation
4 2 3 NULL
5 3 1 EnglishTranslation
5 3 2 NULL
5 3 3 NULL
Need to get translations for all languages by Code from Translations table So far I try
select
T.id, T.Code, L.Id, T.Value
from Languages L
left join Translations T on T.LanguageId = L.Id
but I got not expected result. Could you please suggest
http://sqlfiddle.com/#!6/e9bed/1
You can use CROSS JOIN operator to construct a cartesian product of (LanguageId, Code) pairs, and left-join translation table to it:
SELECT
t.Id, y.Code, x.LanguageId, t.Value
FROM
((SELECT Id AS LanguageId FROM Languages) AS x
CROSS JOIN
(SELECT DISTINCT(Code) AS Code FROM Translations) AS y)
LEFT OUTER JOIN Translations t ON y.Code=t.Code AND x.LanguageId=t.LanguageId
ORDER BY t.Code, t.LanguageId
Note that this wouldn't produce a valid translation Id for rows missing from Translations, i.e. the result would look like this:
Id Code LanguageId Value
---------------------------------------------
1 1 1 EnglishTranslation
NULL 1 2 NULL
2 1 3 RussianTranslation
3 2 1 EnglishTranslation
4 2 2 DeutschTranslation
NULL 2 3 NULL
5 3 1 EnglishTranslation
NULL 3 2 NULL
NULL 3 3 NULL
Demo.
I resolved the issue and got the result that you expected.
Run the below query:
SELECT
(CASE
WHEN T.Id is null and lc.Code = 1 THEN 1
WHEN T.Id is null and lc.Code = 2 THEN 4
WHEN T.Id is null and lc.Code = 3 THEN 5
ELSE T.Id
END) as Id,
lc.Code, lc.Id as LanguageId, T.Value from
(SELECT x.Id, y.Code from (SELECT Id FROM Languages) x cross join (SELECT DISTINCT(Code) as Code FROM Translations) y) as lc
left outer join Translations T ON lc.Id = T.LanguageId and lc.Code = T.Code
order by Id, Code, LanguageId
You can also see the solution in the below link:
http://sqlfiddle.com/#!6/e9bed/30
Hopefully it will work as you like.

Sql server query to join two tables to get desired result set

I have two table Customer-items and Available-locations i need to get the location where all items in customer-items are available.
Customer-items
ItemID ItemName
1 item1
2 item2
3 item3
Available-locations
LocationID ItemID AvailableForPickup
20 1 1
20 2 1
20 3 0
21 1 1
21 2 1
21 3 1
on simple inner join e.g
SELECT * FROM Customer-items
INNER JOIN Available-locations
ON Customer-items.ItemID = Available-locations.ItemsID AND AvailableForPicup = 1
this will exclude item 3 from Available-locations for LocationID 20 but return other two items for locationID 20 and all items for location 21.
i need to get the result set like; to exclude all items for location if any of item is not available.
Available-locations_CustomerItems
LocationID ItemID AvailableForPickup
21 1 1
21 2 1
21 3 1
select * from Customer-items
join Available-locations
on Customer-items.ItemID = Available-locations.ItemsID
where Available-locations.LocationID in
(select LocationID from Available-locations where AvailableForPickup = 1)
Please use the below code. It's working fine with SQL Server 2012.
DECLARE #Customer_Items TABLE (ItemsID int,ItemName VARCHAR(10))
DECLARE #Available_Locations TABLE (LocationID int,ItemsID int,AvailableForPickup int)
INSERT INTO #Customer_Items (ItemsID,ItemName)
VALUES
(1,'item1'),
(2,'item2'),
(3,'item3')
INSERT #Available_Locations
(LocationID,ItemsID, AvailableForPickup)
VALUES
(20,1,1),
(20,2,1),
(20,3,0),
(21,1,1),
(21,2,1),
(21,3,1)
SELECT LocationID,al.ItemsID,AvailableForPickup FROM #Customer_Items ci
INNER JOIN #Available_Locations al
ON ci.ItemsID = al.ItemsID AND al.AvailableForPickup = 1
WHERE al.LocationID NOT IN (SELECT al2.LocationID FROM #Available_Locations al2 WHERE al2.AvailableForPickup =0)
You could use NOT IN in following:
SELECT l.*
FROM [Customer-items] AS i
INNER JOIN [Available-locations] AS l ON i.ItemID = l.ItemID
WHERE l.LocationID NOT IN (SELECT LocationID FROM [Available-locations] WHERE AvailableForPicup = 0)
Note that - is not available in tables names. You have to use brackets [] on table names like [customer-items]. Also use alias names on tables to make It more readable.
OUTPUT
LocationId ItemId AvailableForPickup
21 1 1
21 2 1
21 3 1
SELECT B.ITEMID
,B.LOCATIONID
,B.AVAILABLEFORPICKUP
FROM #A A
RIGHT JOIN #B B ON A.ITEMID = B.ITEMID
WHERE B.AVAILABLEFORPICKUP= 1
SELECT * FROM Customer-items
INNER JOIN Available-locations
ON Customer-items.ItemID = Available-locations.ItemsID AND locationId
NOT IN (select locationID FROM Available-locations WHERE AvailableForPicup = 0)

select data having same id

id idtest result
1 1 2
1 2 1
1 3 2
2 1 2
2 2 1
2 3 1
3 1 1
3 2 2
3 3 1
Would like to get all the rows with the same IDs that matches the condition.
For example: get all the rows with the same id where (idTest=2 and result=1) and (idTest=3 and result=2)
result:
id idtest result
1 1 2
1 2 1
1 3 2
What would be the query???
Thanks!
Do you mean this?
SELECT * FROM table WHERE id = 1 and (result = 1 OR result = 2)
How about his:
SELECT *
FROM table WHERE (idTest = 2 OR idTest = 3) AND (result=1 OR result=2)
ID test res
1 1 2
1 2 1
1 3 2
2 1 1
2 2 2
2 3 2
3 1 1
3 2 2
3 3 1
Sorry. This would be my table. and Would like to get all the rows with the same IDs that matches the condition. For example: get all the rows with the same id where (test=2 and res=1) and (test=3 and res=2)
Result:
ID test res
1 1 2
1 2 1
1 3 2
What would be the query in order to get the three rows ?? Thanks!
You can use EXISTS:
SELECT id, idTest, result
FROM dbo.TableName t
WHERE EXISTS
(
SELECT 1 FROM dbo.TableName t2
WHERE t.id = t2.id
AND(
( t2.idTest=2 AND t2.result=1 )
OR
( t2.idTest=3 AND t2.result=2 )
)
)
Demo
Update: result is different:
id idTest result
1 1 2
1 2 1 <-- satisfies your condition
1 3 2 <-- satisfies your condition
2 1 2
2 2 1 <-- satisfies your condition
2 3 1
So either my understanding was incorrect or your expected result. I have also all ID=2 because the second id-2 row matches the condition.
You seem to want all rows for id's that have rows with that particular combination. What about:
with ids as (
select id
from mytable
where (idTest=2 and result=1) or (idTest=3 and result=2)
group by id
having count(id) = 2
)
select mytable.* from mytable
inner join ids
on ids.id = mytable.id
This gets a list of id's where both conditions apply, and then gets all rows for those id's.
SqlFiddle
SELECT *
FROM table t1
WHERE EXISTS (SELECT 1 FROM table WHERE id = t1.id AND idtest = 2 AND result = 1)
AND EXISTS (SELECT 1 FROM table WHERE id = t1.id AND idtest = 3 AND result = 2)
Just keep adding more AND EXISTS if you need more
Or you can use IN if it makes more sense to you
SELECT *
FROM table
WHERE id IN (SELECT id from table where idtest = 2 and result = 1)
AND id IN (SELECT id from table where idtest = 3 and result = 2)
do you need a method that treats the condition(s) in a generic way, like if they're values in another table? Or do you only need a way to pull results of two independent conditions?
If the latter, then this should work:
SELECT
id
FROM
(SELECT id
FROM tbl
WHERE idTest=2 AND RESULT=1) cond1 INNER JOIN
(SELECT id
FROM tbl
WHERE idTest=3 AND RESULT=2) cond2 ON
cond1.id = cond2.id
otherwise, if your conditions are generic and stored in a table, you'd need something like:
SELECT
id
FROM
(SELECT id
FROM tbl FULL OUTER JOIN conditions c
WHERE c.isUseMe = 1 AND c.SEQ = 1 AND idTest=c.idTestVal AND result=c.resultVal) cond1 INNER JOIN
(SELECT id
FROM tbl FULL OUTER JOIN conditions c
WHERE c.isUseMe = 1 AND c.SEQ = 2 AND idTest=c.idTestVal AND result=c.resultVal) cond2 ON
cond1.id = cond2.id
if the 4 values are passed in as parameters, you'd need something like:
SELECT
id
FROM
(SELECT id
FROM tbl
WHERE idTest=#idTestVal1 AND result=#resultVal1) cond1 INNER JOIN
(SELECT id
FROM tbl
WHERE idTest=#idTestVal2 AND result=#resultVal2) cond2 ON
cond1.id = cond2.id

T-SQL recursive query - how to do it?

I have a table with self referencing relation,
ID parentID UserId Title
1 null 100 A
2 1 100 B
3 2 100 C
4 2 100 D
5 null 100 E
6 5 100 F
I want to update UserId from 100 to 101 for all records with ID=1 and its children, so I want to have
ID parentID UserId Title
1 null 101 A
2 1 101 B
3 2 101 C
4 2 101 D
5 null 100 E
6 5 100 F
How can I do it in T-SQL?
You probably want to use a common table expression which allows you to generate recursive queries.
eg:
;with cte as
(
select * from yourtable where id=1
union all
select t.* from cte
inner join yourtable t on cte.id = t.parentid
)
update yourtable
set userid = 101
where id in (select id from cte)

Avoid repeatation of rows for every instance when joined with a table

Hi i have 3 tables and i am trying to join them to get a desire table. I have tried group by and temp tables options to get the desired table but no help. I want to avoid duplicates for every instance of a value in one table from another table.
Table 1 Customer Table:
CstId CstDetails CstType
---------- --------------- ------------
1 address 1 1
2 address 2 1
3 address 3 1
4 address 4 2
5 address 5 2
Table 2 Customer Relationship:
CstId CstGroupId
---------- ----------------
1 4 (this is same as CustomerId)
2 5 (this is same as CustomerId)
3 4 (this is same as CustomerId)
Table 3 Customer Notes:
CstId NotesId NoteTxt
----------- --------- ---------
1 1 note11
1 2 note12
1 3 note13
3 1 note31
4 1 note41
4 2 note42
4 3 note43
4 4 note44
4 5 note45
Now i want the result to be in the below format
Table result:
(NoteId) (Notetxt) (NoteId) (Notetxt)
CstId CstDetails CstGroupId CstNoteId CstNote CstGroupNoteId CstGroupNote
1 address1 4 1 note11 1 note41
1 address1 4 2 note12 2 note42
1 address1 4 3 note13 3 note43
1 address1 4 null null 4 note44
1 address1 4 null null 5 note45
But i am getting CstGroupNote repeated for all the CstNote, which i am trying to avoid.
Is there a way i could achieve this result?
Below is the code i use:
select c.cstid, c.cstdetails, cn.cstnotesid, cn.cstnotetxt
insert into temp1
from customer c
left outer join customernotes cn
on c.cstid = cn.cstid
where c.customertypeid = 1
select cr.cstid, cr.cstgroupid, cn.cstgroupnoteid, cn.cstnotetxt
insert into temp2
from customerrelationship cr
left outer join customernotes cn
on cr.cstgroupid = cn.customerid
select t1.cstid, t1.cstdetails, t1.cstnotesid, t1.cstnotetxt, t2.cstgroupnoteid, t2.cstnotetext
from temp1 t1
left outer join t2
on t1.cstid = t2.cstid
Try:
select CstId,
max(CstDetails) CstDetails,
max(CstGroupId) CstGroupId,
max(CstNoteId) CstNoteId,
max(CstNote) CstNote,
max(CstGroupNoteId) CstGroupNoteId,
max(CstGroupNote) CstGroupNote
from
(select c.CstId,
c.CstDetails,
0 CstGroupId,
n.NotesId CmbNotesId,
n.NotesId CstNoteId,
n.NoteTxt CstNote,
0 CstGroupNoteId,
'' CstGroupNote
from customer c
left outer join customernotes n on c.cstid = n.cstid
where c.customertypeid = 1
union all
select c.CstId,
c.CstDetails,
r.CstGroupId,
n.NotesId CmbNotesId,
0 CstNoteId,
'' CstNote,
n.NotesId CstGroupNoteId,
n.NoteTxt CstGroupNote
from customer c
left outer join customerrelationship r on c.cstid = r.cstid
left outer join customernotes n on r.CstGroupId = n.cstid
where c.customertypeid = 1) u
group by CstId, CmbNotesId
Use a derived table and an outer join
The trick there is the
and cn.cstnotesid = cG.cstnotesid
to link those two on one row
select c.cstid, c.cstdetails, cn.cstnotesid, cn.cstnotetxt
,cG.CstGroupId, cG.cstnotesid, cG.cstnotetxt
from customer c
join customernotes cn
on cn.cstid = c.cstid
outer join (select c.cstid, c.CstGroupId, cn.cstnotesid, cn.cstnotetxt
from customer c
join customernotes cn
on cn.cstid = c.CstGroupId) as cG
on c.cstid = cG.cstid
and cn.cstnotesid = cG.cstnotesid
order by c.cstid, cn.cstnotesid, cG.cstnotesid