TSQL A problem with categories tree - tsql

I have a problem with recursive CTE query
Let's say that I have that category tree (Category table)
In my CTE query, I search for all children of the 1 category:
(that query works fine)
with mq as
(
select c.Id as parent, c.Id as child
from dbo.Category c
where c.Id = 1
union all
select q.child, c.Id
from mq q
inner join dbo.Category c on q.child = c.IdParentCategory
)
The output
Then, I want to get that Category ID, wchih doesn't have a child: categories 9,10,12,14,15
with mq as
(
select c.Id as parent, c.Id as child
from dbo.Category c
where c.Id = 1
union all
select q.child, c.Id
from mq q
inner join dbo.Category c on q.child = c.IdParentCategory
where child in
(
select c1.Id
from dbo.Category c1
where not exists(select c2.Id
from dbo.Category c2
where c2.Id = c1.IdParentCategory)
)
)
but the output is wrong:
why ? Any ideas will be helpful !
if I separate the query from CTE, everything is OK
declare #tab table
(parent int, child int);
insert into #tab
select * from mq
delete from #tab
where child in (
select c1.parent
from #tab c1
where not exists(select c2.parent from #tab c2 where c2.parent = c1.child)
)

with mq as
(
select c.Id as parent, c.Id as child
from dbo.Category c
where c.Id = 1
union all
select q.child, c.Id
from mq q
inner join dbo.Category c on q.child = c.IdParentCategory
)
select child from mq where child not in (select parent from mq)
Would seem to give the output you want - in fact your description of the problem almost took this form.

Related

[PostgreSQL]: Subquery has too many columns

I am trying to run a query, but the result is showing the error message "Subquery has too many columns". I have to change where the clause with array to string but the error is the same. could you help me, if you have any suggestions or different queries as modify to solve this?
the query is:
create table my_schema.table_1 as select a.*
, O.ID1
, J.ID2
, K.ID3
, L.ID4
, M.ID5
, S.ID6
, O.plan_name plan_name1
, J.plan_name plan_name2
, K.plan_name plan_name3
, L.plan_name plan_name4
, M.plan_name plan_name5
, S.plan_name plan_name6
from (
select
PRD_ID
, NBR
, SI
, START_TIME
, ATTR4
, G_ID
, BYTE_UP
, BYTE_DOWN
, LIST
, TYPE_ID1
, TYPE_ID2
, TYPE_ID3
, TYPE_ID4
, TYPE_ID5
, TYPE_ID6
, CHARGE1, CHARGE2, CHARGE3, CHARGE4, CHARGE5, CHARGE6
from my_schema.source where prd_id = '20200101'
and TYPE IN (3) ) a
left outer join (select distinct id, price_plan_name from my_schema.id_ref_v9) O on split_part(split_part(list,';',1),',',1) = O.id
left outer join (select distinct id, price_plan_name from my_schema.id_ref_v9) J on split_part(split_part(list,';',2),',',1) = J.id
left outer join (select distinct id, price_plan_name from my_schema.id_ref_v9) K on split_part(split_part(list,';',3),',',1) = K.id
left outer join (select distinct id, price_plan_name from my_schema.id_ref_v9) L on split_part(split_part(list,';',4),',',1) = L.id
left outer join (select distinct id, price_plan_name from my_schema.id_ref_v9) M on split_part(split_part(list,';',5),',',1) = M.id
left outer join (select distinct id, price_plan_name from my_schema.id_ref_v9) S on split_part(split_part(list,';',6),',',1) = S.id
WHERE (
O.id in (select * from my_schema.LIST_PRICEID4)or
J.id in (select * from my_schema.LIST_PRICEID4)or
K.id in (select * from my_schema.LIST_PRICEID4)or
L.id in (select * from my_schema.LIST_PRICEID4)or
M.id in (select * from my_schema.LIST_PRICEID4)or
S.id in (select * my_schema.LIST_PRICEID4))

ERROR. saying that film_id must appear in the GROUP BY clause

SELECT film_id, film_actor.actor_id,first_name,last_name,COUNT(*)
FROM film_actor
INNER JOIN actor ON film_actor.actor_id=actor.actor_id
GROUP BY film_actor.actor_id ;
SELECT
film_id,? ---(Which table ? you can neglect)
film_actor.actor_id,
first_name,
last_name,
COUNT(*) AS Total
FROM film_actor
INNER JOIN actor
ON film_actor.actor_id =actor.actor_id
GROUP BY film_actor.actor_id ;
Best practice for this SQL statement will be like
SELECT
c.film_id,
a.actor_id,
b.first_name,
b.last_name
a.Count
FROM
(
SELECT
film_actor.actor_id,
COUNT(*) AS Count
FROM film_actor
INNER JOIN actor
ON film_actor.actor_id =actor.actor_id
GROUP BY film_actor.actor_id ;
) AS a
INNER JOIN actor b ON b.actor_id = a.actor_id
INNER JOIN film_actor c ON c.actor_id = a.actor_id

T-SQL: how to sort table rows based on 2 columns

I'm quite stuck with this problem for sometime now..
How do I sort column A depending on the contents of Column B?
I have this sample:
ID count columnA ColumnB
-----------------------------------
12 1 A B
13 2 C D
14 3 B C
I want to sort it like this:
ID count ColumnA ColumnB
-----------------------------------
12 1 A B
14 3 B C
13 2 C D
so I need to sort the rows if the previous row of ColumnB = the next row of ColumnA
I'm thinking a loop? but can't quite imagine how it will work...
I was thinking it will go like this (maybe)
SELECT
a.ID, a.ColumnA, a.ColumnB
FROM
TableA WITH a (NOLOCK)
LEFT JOIN
TableA b WITH (NOLOCK) ON a.ID = b.ID AND a.counts = b.counts
WHERE
a.columnB = b.ColumnA
the above code isn't working though and I was thinking more on the lines of...
DECLARE #counts int = 1
DECLARE #done int = 0
--WHILE #done = 0
BEGIN
SELECT
a.ID, a.ColumnA, a.ColumnB
FROM
TableA WITH a (NOLOCK)
LEFT JOIN
TableA b WITH (NOLOCK) ON a.ID = b.ID AND a.counts = #counts
WHERE
a.columnB = b.ColumnA
set #count = #count +1
END
If this was a C code, would be easier for me but T-SQL's syntax is making it a bit harder for a noobie like me.
Any help is greatly appreciated!
Edit: sample code
drop table tablea
create table TableA(
id int,
colA varchar(10),
colb varchar(10),
counts int
)
insert INTO TableA
(id, cola, colb, counts)
select 12, 'Bad', 'Cat', 3
insert INTO TableA
(id, cola, colb, counts)
select 13, 'Apple', 'Bad', 1
insert INTO TableA
(id, cola, colb, counts)
select 14, 'Cat', 'Dog', 2
select * FROM TableA
SELECT a.ID, a.ColA, a.ColB
FROM TableA a WITH (NOLOCK)
LEFT JOIN TableA b WITH (NOLOCK)
ON a.ID = b.ID
Where a.colB = b.ColA
ORDER BY a.ColA ASC
you just need to add ORDER BY clause
-- SELECT a.ID, a.ColumnA, a.ColumnB
-- FROM TableA WITH a (NOLOCK)
-- LEFT JOIN TableA b WITH (NOLOCK)
-- ON a.ID = b.ID
-- and a.counts = b.counts
-- Where a.columnB = b.ColumnA
ORDER BY a.ColumnA ASC
This is all you need. Sometimes you have to think simple
select * from table A
order by columnA asc

sql server 2005/2008 conditional join

Is there such thing like conditional join:
SELECT *
FROM TABLE1 A
IF (a=='TABLE2') THEN INNER JOIN TABLE2 B ON A.item_id=B.id
ELSE IF (a=='TABLE3') THEN INNER JOIN TABLE3 C ON A.item_id=C.id
While a is a field in TABLE1.
I like to use this in stored procedures without using dynamic sql (without writing query as string and EXEC(#query)).
EDIT: I can't write:
IF (a=='TABLE2) THEN queryA
ELSE IF (a=='TABLE3') THEN queryB
Because a is a field of TABLE1.
EDIT: Modified answer based on comment below:
You could try to get clever with some left joins. This will return more columns, so you'd probably want to be more discriminating than just SELECT *.
SELECT *
FROM TABLE1 A
LEFT JOIN TABLE2 B
ON A.item_id = B.id
AND A.a = 'TABLE2'
LEFT JOIN TABLE3 C
ON A.item_id = C.id
AND A.a = 'TABLE3'
WHERE (B.id IS NOT NULL AND A.a = 'TABLE2')
OR (C.id IS NOT NULL AND A.a = 'TABLE3')
Updated the query as requried:
SELECT * FROM
(
SELECT *
FROM TABLE1 A INNER JOIN TABLE2 B
ON A.a='TABLE2' --This will eleminate the table rows if the value of A.a is not 'TABLE2'
AND A.item_id=B.id) A,
(SELECT * FROM
INNER JOIN TABLE3 C
ON A.a='TABLE3' --This will eleminate the table rows if the value of A.a is not 'TABLE3'
AND A.item_id=C.id
) B
) a

How to use "as" to set alias for joined tables in oracle 10

I wrote this, and it is wrong syntax, help me fix it, I want 'T' to be an alias of the result of the two inner joins.
select T.id
from table1
inner join table2 on table1.x = table2.y
inner join table3 on table3.z = table1.w as T;
You cannot use aliases to name the "entire" join, you can, however, put aliases on individual tables of the join:
select t1.id
from table1 t1
inner join table2 t2 on t1.x = t2.y
inner join table3 t3 on t3.z = t1.w
In the projection, you will have to use the alias of the table, which defines the id column you are going to select.
You can't directly name the result of a join. One option is to use a subquery:
select T.id
from (
select *
from table1
inner join table2 on table1.x = table2.y
inner join table3 on table3.z = table1.w
) T
Another option is subquery factoring:
with T as (
select *
from table1
inner join table2 on table1.x = table2.y
inner join table3 on table3.z = table1.w
)
select T.id
from T