Users with their child count - sql

I have a table like this:
Userid Name ParentId
1 A Null
2 B 1
3 C 1
4 D 2
5 E 3
so output should be like this:
UserId Name Childs
1 A 2 // A has two children B and C
2 B 1 // B has one child D
3 C 1 // C has one child E
So please help and let me know if any confusion?

Try this
SELECT t1.UserId, t1.Name, count(t2.UserId)
FROM table t1
INNER JOIN table t2 ON t2.parentid = t1.UserId
GROUP BY t1.UserId, t1.Name

DECLARE #test Table
(ID INT, Name VARCHAR(20),CID INT)
INSERT INTO #test
VALUES
(1, 'A',NULL),
(2, 'B',1),
(3, 'C' ,1),
(1, 'D',2),
(2, 'E',3);
;WITH CTE AS
(
select ID,Name from #test
)
select c.ID,c.Name,COUNT(t.ID) from CTE C
INNER JOIN #test t
ON t.CID = c.ID
GROUP by c.ID,c.Name

Related

How can I override rows from another table?

I have two tables:
TableA
ID Name
-- ----
1 aaa
2 bbb
3 ccc
4 ddd
TableB
ID Name
-- --------
3 WWXXYYZZ
I want to select from both tables, but skip the rows which exist in TableB. The result should look like this:
ID Name
-- --------
1 aaa
2 bbb
3 WWXXYYZZ
4 ddd
I have tried union and join but did not figure out how to achieve this.
-- Did not work
select *
from TableA
union
select *
from TableB
-- Did not work
select *
from
(
select *
from TableA
) x
join
(
select *
from TableB
) y
on x.ID = y.ID
You could left join b on to a, and use coalesce to prefer b's rows:
SELECT a.id, COALESCE(b.name, a.name) AS name
FROM a
LEFT JOIN b ON a.id = b.id
You can do:
select a.id, coalesce(b.name, a.name)
from a left join b on a.id = b.id
One method is union all:
select b.*
from b
union all
select a.*
from a
where not exists (select 1 from a where a.id = b.id);
You can also choose from a and override with values from b:
select a.id, coalesce(b.name, a.name) as name
from a left join
b
on a.id = b.id;
A more complex method uses ROW_NUMBER which might be necessary if your query is significantly more complex than shown. It also handled the case where a row exists in TableB but not TableA (which is not clear from your question).
DECLARE #TableA TABLE (id INT, [Name] VARCHAR(12));
DECLARE #TableB TABLE (id INT, [Name] VARCHAR(12));
INSERT INTO #TableA (id, [Name])
VALUES
(1, 'aaa'),
(2, 'bbb'),
(3, 'ccc'),
(4, 'ddd');
INSERT INTO #TableB (id, [Name])
VALUES
(3, 'WWXXYYZZ'),
(5, 'TTTGGG');
SELECT id, [Name]
FROM (
SELECT id, [Name]
, ROW_NUMBER() OVER (PARTITION BY id ORDER BY [Priority] DESC) Rn
FROM (
SELECT id, [Name], 0 [Priority]
FROM #TableA
UNION ALL
SELECT id, [Name], 1 [Priority]
FROM #TableB
) X
) Y
WHERE Rn = 1;
Returns:
1 aaa
2 bbb
3 WWXXYYZZ
4 ddd
5 TTTGGG

count of row by row from another table holding some conditions on both tables in sql

There are two tables Table1 and Table2
A B C S
a 1 21 Summer
b 2 22 Summer
c 3 34 Summer
D E F S
a 1 21 Summer
d 5 22 Summer
f 2 34 Summer
I wanted to fetch all columns of Table first and count of column F from table second based on conditions such as column B OF table first is less than values of column E of table second.
I tried this query
select a.*,
(select count(F) from Table2 JOIN Table1 on table1.S=table2.S where table1.B<table2.E ) AS Cnt
from Table1 a
However it is giving me same count for all rows which is incorrect
I need count based on condition fulfilled.
This will work
DECLARE #T1 TABLE (A Varchar(10), B INT, C INT, S Varchar(10))
DECLARE #T2 TABLE (D Varchar(10), E INT, F INT, S Varchar(10))
INSERT INTO #T1 VALUES
('a', 1, 21,'Summer'),
('b', 2 ,22,'Summer'),
('c', 3, 34,'Summer')
INSERT INTO #T2 VALUES
('a', 1, 21,'Summer'),
('d', 5 ,22,'Summer'),
('f', 2 ,34,'Summer')
SELECT
T1.A,T1.B,T1.C,T1.S,
COUNT(T2.S) as Counts
FROM #T1 T1
left JOIN #T2 T2
ON T1.S = T2.S AND T1.B < T2.E
GROUP BY T1.A,T1.B,T1.C,T1.S
Output
A B C S Counts
a 1 21 Summer 2
b 2 22 Summer 1
c 3 34 Summer 1
select *,
(select count(F)
from T2
where T1.S = T2.S AND T1.B < T2.E
) as Cnt from T1
I think you just want a correlated subquery:
select a.*,
(select count(t2.F)
from Table2 t2
where a.S = t2.S and t1.B < t2.E
) as Cnt
from Table1 a

Distribute a header table value to another table several rows with the same id

I need help with SQL Server on how to distribute a header table value to another table several rows with the same id : -
Table A : -
Id | Value
---+--------
1 | 40
2 | 21
Table B : -
Id | Qty
---+-------
1 | 20
1 | 13
2 | 1
Result should be : -
Id | Value | Qty
--------------------
1 | 20 | 20
1 | 20 | 13
2 | 21 | 1
WITH TblA
AS (SELECT 1 AS id,
40 AS num
UNION
SELECT 2,
21),
TblB
AS (SELECT 1 AS id,
20 AS num
UNION
SELECT 1,
13
UNION
SELECT 2,
1)
SELECT *
FROM TblA a
INNER JOIN TblB b ON a.id = b.id;
This below logic will distribute the value equally to all rows.
SELECT *,
(SELECT Value FROM A WHERE A.id = B.id)/COUNT(*) OVER(PARTITION BY id) Value
FROM B
Output is-
Id Qty Value
1 13 20
1 20 20
2 1 21
But if you wants to distribute the same value for all rows, do this below-
SELECT *,
(SELECT Value FROM A WHERE A.id = B.id) Value
FROM B
OR
SELECT B.*,A.Value
FROM B
INNER JOIN A ON B.id= A.id
Output will be-
Id Qty Value
1 20 40
1 13 40
2 1 21
Substitute table variables #Header & #Detail with your tables and remove the insert statements. You could also do this with a sub query to your main query as proposed in some of the other answers but for larger tables it may become slow hence the table variable called #Counter to first gather the aggregated count based on the #Detail table variable.
declare #Header table
(
Id int identity(1, 1),
[Value] int
)
declare #Detail table
(
Id int identity(1, 1),
HeaderId int,
Qty int
)
declare #Counter table
(
HeaderId int,
[Count] int
)
insert into #Header values (40)
insert into #Header values (21)
insert into #Detail values (1, 20)
insert into #Detail values (1, 13)
insert into #Detail values (2, 1)
insert into #Counter
select d.HeaderId, count(d.HeaderId)
from #Detail d
group by d.HeaderId
select
h.Id,
h.[Value] / c.[Count] [Value],
d.Qty
from #Header h
join #Detail d
on h.Id = d.HeaderId
join #Counter c
on h.Id = c.HeaderId
Please try with this simple Join
SELECT ta.id,
ta.value / (SELECT ( Count(tmp.id) )
FROM tb AS tmp
WHERE tmp.id = ta.id
GROUP BY tmp.id) AS 'value',
tb.qty
FROM ta
INNER JOIN tb
ON ta.id = tb.id
Full example (check Image):
CREATE TABLE ta
(
id INT,
value INT
)
CREATE TABLE tb
(
id INT,
qty INT
)
INSERT INTO ta
VALUES (1,40),
(2,21)
SELECT *
FROM ta
INSERT INTO tb
VALUES (1,20),
(1,13),
(2,1)
SELECT *
FROM tb
SELECT *
FROM ta
SELECT *
FROM tb
SELECT ta.id,
ta.value / (SELECT ( Count(tmp.id) )
FROM tb AS tmp
WHERE tmp.id = ta.id
GROUP BY tmp.id) AS 'value',
tb.qty
FROM ta
INNER JOIN tb
ON ta.id = tb.id
Just use a window function to divide the value:
select tb.id, ta.value / count(*) over (partition by ta.id) as value, tb.qty
from ta join
tb
on ta.id = tb.id;
Note that because these are integers, you might want to avoid integer division by using:
select tb.id, ta.value * 1.0 / count(*) over (partition by ta.id) as value, tb.qty
Here is a db<>fiddle.

Full Outer Join on Incomplete Data (by id variable)

I have two tables (see example data below). I need to keep all of the ID values in table 1 and merge table 1 with table 2 by sequence. The tricky part is that I also have to retain the field value1 from table 1 and value2 from table 2.
table 1 :
ID sequence value1
-------------------------
p1 1 5
p1 2 10
p2 1 15
p2 2 20
table 2 :
sequence value2
-------------------------
1 10
2 20
3 30
4 40
I need the resulting table to appear like so:
ID sequence value1 value2
----------------------------------
p1 1 5 10
p1 2 10 20
p1 3 - 30
p1 4 - 40
p2 1 15 10
p2 2 20 20
p2 3 - 30
p2 4 - 40
I have tried the following sql code, but it doesn't merge the missing values from from value1 field in table 1 and merge it with the values2 field from table 2
select t1.ID, t2.sequence, t1.value1, t2.value2 from
t2 full outer join t1 on t2.sequence=t1.sequence
Any assistance you can provide is greatly appreciated.
You can try something like this:
select coalesce(t1.[id], t3.[id]),
, t2.[sequence]
, t1.[value]
, t2.[value]
from [tbl2] t2
left join [tbl1] t1 on t1.[sequence] = t2.[sequence]
left join (select distinct [id] from [tbl1]) t3 on t1.[id] is null
SQLFiddle
One way with CROSS JOIN and OUTER APPLY:
DECLARE #t1 TABLE(ID CHAR(2), S INT, V1 INT)
DECLARE #t2 TABLE(S INT, V2 INT)
INSERT INTO #t1 VALUES
('p1', 1, 5),
('p1', 2, 10),
('p2', 1, 15),
('p2', 2, 20)
INSERT INTO #t2 VALUES
(1, 10),
(2, 20),
(3, 30),
(4, 40)
SELECT c.ID, t2.S, ca.V1, t2.V2 FROM #t2 t2
CROSS JOIN (SELECT DISTINCT ID FROM #t1) c
OUTER APPLY(SELECT * FROM #t1 t1 WHERE c.ID = t1.ID AND t1.S = t2.S) ca
ORDER BY c.ID, t2.S
Output:
ID S V1 V2
p1 1 5 10
p1 2 10 20
p1 3 NULL 30
p1 4 NULL 40
p2 1 15 10
p2 2 20 20
p2 3 NULL 30
p2 4 NULL 40
Given this schema:
create table #table_1
(
ID varchar(8) not null ,
sequence int not null ,
value int not null ,
primary key clustered ( ID , sequence ) ,
unique nonclustered ( sequence , ID ) ,
)
create table #table_2
(
sequence int not null ,
value int not null ,
primary key clustered ( sequence ) ,
)
go
insert #table_1 values ( 'p1' , 1 , 5 )
insert #table_1 values ( 'p1' , 2 , 5 )
insert #table_1 values ( 'p2' , 1 , 15 )
insert #table_1 values ( 'p2' , 2 , 20 )
insert #table_2 values ( 1 , 10 )
insert #table_2 values ( 2 , 20 )
insert #table_2 values ( 3 , 30 )
insert #table_2 values ( 4 , 40 )
go
This should get you what you want:
select ID = map.ID ,
sequence = map.sequence ,
value1 = t1.value ,
value2 = t2.value
from ( select distinct
t1.ID ,
t2.sequence
from #table_1 t1
cross join #table_2 t2
) map
left join #table_1 t1 on t1.ID = map.ID
and t1.sequence = map.sequence
join #table_2 t2 on t2.sequence = map.sequence
order by map.ID ,
map.sequence
go
Producing:
ID sequence value1 value2
== ======== ====== ======
p1 1 5 10
p1 2 5 20
p1 3 - 30
p1 4 - 40
p2 1 15 10
p2 2 20 20
p2 3 - 30
p2 4 - 40

Query to count the entries

I have two tables like this.
A B
1 12
2 13
3 12
4 13
5 15
B C
12 APPLE
13 ORANGE
14 MANGO
15 BANANA
I need output as below...
count(A) B C
2 12 APPLE
2 13 ORANGE
0 14 MANGO
1 15 BANANA
I have written the query using joins but I am stuck at displaying the count as zero in case of empty value.
Use a left join to get the values of table2 even if there are no records for them in table1
select T2.B, T2.C, count(T1.A)
from table2 T2
left join table1 T1 on T1.B = T2.B
group by T2.B, T2.C
Try this:
SELECT COUNT(T1.A) as Cnt,T2.B,T2.C
FROM Table2 T2 LEFT JOIN
Table1 T1 ON T1.B=T2.B
GROUP BY T2.B,T2.C
Result:
CNT B C
2 12 APPLE
1 15 BANANA
0 14 MANGO
2 13 ORANGE
See result in SQL Fiddle.
Just to give you another option. You don't need a join, as you only want to show table2 records along with another value which you can get in a sub-query.
select (select count(*) from table1 where table1.B = table2.B) as cnt, B, C
from table2
order by B;
There are other ways to do it (using subquery), but I would use this following one:
-- SETUP
CREATE TABLE #TABLE1 (A INT, B INT);
CREATE TABLE #TABLE2 (B INT, C CHAR(10));
INSERT #TABLE1
SELECT 1, 12 UNION ALL
SELECT 2, 13 UNION ALL
SELECT 3, 12 UNION ALL
SELECT 4, 13 UNION ALL
SELECT 5, 15
INSERT #TABLE2
SELECT 12, 'APPLE' UNION ALL
SELECT 13, 'ORANGE' UNION ALL
SELECT 14, 'MANGO' UNION ALL
SELECT 15, 'BANANA'
-- query
SELECT COUNT(qty.A), dsc.B, dsc.C
FROM #TABLE2 dsc
LEFT JOIN #TABLE1 qty ON (dsc.B = qty.B)
GROUP BY dsc.B, dsc.C
ORDER BY dsc.B, dsc.C;
DECLARE #TABLE1 TABLE (A INT, B INT)
INSERT INTO #TABLE1 VALUES
(1, 12),
(2, 13),
(3, 12),
(4, 13),
(5, 15)
DECLARE #TABLE2 TABLE (B INT, C VARCHAR(20))
INSERT INTO #TABLE2 VALUES
(12,'APPLE'),
(13,'ORANGE'),
(14,'MANGO'),
(15,'BANANA')
SELECT t2.C
,ISNULL(COUNT(t1.B), 0) total_Count
FROM #TABLE2 t2 LEFT JOIN #TABLE1 t1
ON t2.B = t1.B
GROUP BY t2.C
C total_Count
APPLE 2
BANANA 1
MANGO 0
ORANGE 2