How to get the Count of the subgroup in SQL - sql

How can I get the Count of the subgroup. I have Table1 and Table2 (below). How can I get the table Result. I tired group by but only manage to get the total rows. I am trying it in Microsoft SQL.
Table1
ID PriID Function
1 500 A
2 500 B
3 500 C
4 501 A
5 501 B
6 502 C
7 503 A
Table2
PriID Color
500 Green
501 Red
502 Green
503 Green
Result
Function Green Red Total
A 2 1 3
B 1 1 2
C 2 0 2
below is the current one I tried
SELECT t1.Function, Count(t1.PriID) as Total FROM Table1 t1
LEFT JOIN Table2 t2 on t1.PriID = t2.PriID
GROUP BY t1.function
and I get this
Result
Function Total
A 3
B 2
C 2

Try this
SELECT t1.Function,
SUM(CASE WHEN Color = 'Green' THEN 1 ELSE 0 END) AS Green,
SUM(CASE WHEN Color = 'Red' THEN 1 ELSE 0 END) AS Red,
Count(t1.PriID) as Total FROM Table1 t1
LEFT JOIN Table2 t2 on t1.PriID = t2.PriID
GROUP BY t1.function

This is the best approach for doing this stuff
;with cte as
(
select [Function],t1.priID,color
from tbl1 t1
join tbl2 t2 on t1.priID = t2.priid
),def as
(
select [Function],[Green],[Red]
from
(
select [Function],color,priID from cte) dk
Pivot (count(priID) for color in([Green],[Red] )
) pvt
) select *,green+red [Total] from def

select [function], ISNULL(Green, 0) Green, ISNULL(Red, 0) Red,
ISNULL(Green, 0) + ISNULL(Red, 0) Total
from
(
select *, count([function]) 'X' from
(
select t2.color, t1.[function] from table1 t1
JOIN table2 t2 on t1.prid = t2.prid
)A
group by color, [function]
)B pivot (max(X) for color IN ([Green],[Red]))as d

Try this:
;with cte as
(select [function],
Sum(CASE WHEN t1.PriId <> 501 Then 1 Else 0 END) over(partition by [function] order by t1.priid) Green,
Sum(CASE WHEN t1.PriId = 501 Then 1 Else 0 END) over(partition by [function] order by t1.priid) Red,
Count(*) over (partition by [function] order by t1.priid) Total,
Row_Number() over (partition by [function] order by t1.priid desc) rn
from
table1 t1
left join table2 t2 on t1.priid = t2.priid)
select [function],green,red,total
from cte
where rn = 1
This query uses windowing functions (available from SQL Server 2005 onwards), which eliminates the need for a GROUP BY clause
Demo

Hi you should use PIVOT to get result. Like this:
CREATE TABLE #table (id int, priID int, [FUNCTION] varchar(5))
INSERT INTO #table ( id,priID,[FUNCTION] )
VALUES ( 1, 500,'a' ), ( 2, 500,'b' ), ( 3, 500,'c' ), ( 4, 501,'a' ), ( 5, 501,'b' ), ( 6, 502,'c' )
CREATE TABLE #table2 (priID int, color varchar(20))
INSERT INTO #table2 (priID,color )
VALUES ( 500,'green' ), ( 501, 'red' ), ( 502,'yellow' )
SELECT t.[FUNCTION], t2.color, COUNT(t.priID) AS cnt
INTO #result
FROM #table AS T
INNER JOIN #table2 AS T2 ON T2.priID = T.priID
GROUP BY t.[FUNCTION], t2.color
SELECT [FUNCTION], green, red, yellow
FROM ( SELECT [FUNCTION], color, cnt
FROM #result AS R) AS p
PIVOT ( MAX(cnt) FOR color IN (green, red, yellow)) AS pvt
http://rextester.com/ROPBBS57014

The best way for all records in table (If you edit, delete or insert new one) is:
With t (F,PriID,Color) as
(
SELECT Table1.F, Table2.PriID, Table2.Color
FROM Table1 INNER JOIN
Table2 ON Table1.PriID = Table2.PriID
GROUP BY Table2.PriID,F,Color)
select F,Color,COUNT(F) as total from t group by F,Color
And you get this:
Result
Function Color total
A Green 2
B Green 1
C Green 2
A Red 1
B Red 1

Related

Find only those ID's where color are same on all rows

id color
1 Yellow
1 Pink
2 Yellow
2 blue
3 Yellow
3 Yellow
4 Red
Want only those ID's where color are same for all rows.
Have tried multiple way but didn't get any answer.
;WITH CTE AS (
select ROW_NUMBER() OVER(PARTITION BY A.ID,A.COLOR ORDER BY A.ID,A.COLOR)RNO,A.ID,A.COLOR from COLOR a join COLOR b on a.id = b.id and a.color=b.color
)
SELECT DISTINCT ID, COLOR FROM CTE --WHERE RNO > 1
SELECT *
FROM color a join (
SELECT id, color, count(*) as qty
FROM color
GROUP BY id, color
HAVING COUNT(*) > 1
) b on a.id = b.id and a.color = b.color
select * from (
Select color,id,count(1)cnt from COLOR
group by color,id
having count(1) = 1
union all
Select color,id,count(1)cnt from COLOR
group by color,id
having count(1) > 1
) as t where cnt between 1 and 4
GROUP BY with HAVING will do the job. COUNT(DISTINCT color) will return distinct colors in each group, If it returns 1, then we have one color for all rows in a group.
select id from my_table
group by id
having count(distinct color) = 1
You can use not exists :
select c.*
from color c
where not exists (select 1 from color c1 where c1.id = c.id and c1.color <> c.color);

MS-SQL max ID with inner join

Can't see the wood for the trees on this and I'm sure it's simple.
I'm trying to return the max ID for a related record in a joined table
Table1
NiD
Name
1
Peter
2
John
3
Arthur
Table2
ID
NiD
Value
1
1
5
2
2
10
3
3
10
4
1
20
5
2
15
Max Results
NiD
ID
Value
1
4
20
2
5
15
3
3
10
You can use row_number() for this:
select NiD, ID, Value
from (select t2.*,
row_number() over (partition by NiD order by ID desc) as seqnum
from table2 t2
) t2
where seqnum = 1;
As the question is stated, you do not need table1, because table2 has all the ids.
This is how I'd do it, I think ID and Value will be NULL when Table2 does not have a corresponding entry for a Table1 record:
SELECT NiD, ID, [Value]
FROM Table1
OUTER APPLY (
SELECT TOP 1 ID, [Value]
FROM Table2
WHERE Table1.NiD = Table2.NiD
ORDER BY [Value] DESC
) AS Top_Table2
CREATE TABLE Names
(
NID INT,
[Name] VARCHAR(MAX)
)
CREATE TABLE Results
(
ID INT,
NID INT,
VALUE INT
)
INSERT INTO Names VALUES (1,'Peter'),(2,'John'),(3,'Arthur')
INSERT INTO Results VALUES (1,1,5),(2,2,10),(3,3,10),(4,1,20),(5,2,15)
SELECT a.NID,
r.ID,
a.MaxVal
FROM (
SELECT NID,
MAX(VALUE) as MaxVal
FROM Results r
GROUP BY NID
) a
JOIN Results r
ON a.NID = r.NID AND a.MaxVal = r.VALUE
ORDER BY NID
Here's what I have used in similar situations, performance was fine, provided that the data set wasn't too large (under 1M rows).
SELECT
table1.nid
,table2.id
,table2.value
FROM table1
INNER JOIN table2 ON table1.nid = table2.nid
WHERE table2.value = (
SELECT MAX(value)
FROM table2
WHERE nid = table1.nid)
ORDER BY 1

Is it possible to JOIN a table on the TOP 1 if there is no unique identifier?

For Example
SELECT
a.SomethingInCommon,
tbl1.Status AS Status1,
tbl2.Status AS Status2,
tbl3.Status AS Status3
FROM Maintable a
LEFT OUTER JOIN SecondTable tbl1 ON
tbl1.ID = (SELECT TOP 1 ID
FROM SecondTable SomethingInCommon = a.SomethingInCommon)
LEFT OUTER JOIN SecondTable tbl2 ON
tbl2.ID = (SELECT TOP 1 ID
FROM SecondTable WHERE SomethingInCommon = a.SomethingInCommon
AND ID NOT IN (SELECT TOP 1 ID
FROM SecondTABLE
WHERE SomethingInCommon = a.SomethingInCommon))
LEFT OUTER JOIN SecondTable tbl3 ON
tbl23.ID = (SELECT TOP 1 ID
FROM SecondTable
WHERE SomethingInCommon = a.SomethingInCommon
AND ID NOT IN (SELECT TOP 2 ID
FROM SecondTABLE WHERE SomethingInCommon = a.SomethingInCommon))
This query joins SecondTable three times to show a record like
SomethingInCommon | Status1 | Status2 | Status 3
Is there anyway to accomplish these results if SecondTable does not have the unique identifier column (ID) ?
Perhaps maybe creating a temporary unique ID on the fly?
If you don't have IDs but know the order you want, you could create artificial IDs using ROW_NUMBER() and then do your TOP 1's off of that.
WITH TEMP AS (
SELECT 3 a, 1 b UNION ALL
SELECT 2, 1 UNION ALL
SELECT 1, 1 UNION ALL
SELECT 2, 2 UNION ALL
SELECT 1, 2)
SELECT A, B, ROW_NUMBER() OVER (PARTITION BY B ORDER BY B ASC) as RowNumber FROM TEMP
;WITH TEMP AS (
SELECT 3 a, 1 b UNION ALL
SELECT 2, 1 UNION ALL
SELECT 1, 1 UNION ALL
SELECT 2, 2 UNION ALL
SELECT 1, 2)
SELECT A, B, ROW_NUMBER() OVER (ORDER BY A ASC) as RowNumber FROM TEMP
As Raphael said in the comment, this can be done with CTE like below
with cte
as
(
SELECT M.SomethingInCommon, S.ID, ROW_NUMBER() OVER ( Partition by S.SomethingInCommon ORDER BY S.ID desc) as rn
FROM Maintable M
LEFT JOIN SecondTable S
on M.SomethingInCommon = S.SomethingInCommon
)
SELECT cte.SomethingInCommon
case when rn =1 then cte.ID end as Status1,
case when rn =2 then cte.ID end as Status2,
case when rn =3 then cte.ID end as Status3
where rn <=3
If you want the top three statuses, then you can use conditional aggregation:
select m.somethingincommon,
max(case when seqnum = 1 then status end) as status1,
max(case when seqnum = 2 then status end) as status2,
max(case when seqnum = 3 then status end) as status3
from maintable m left join
(select s.*,
row_number() over (partition by s.somethingincommon order by (select NULL)) as seqnum
from secondtable
) s
on m.somethingincommon = s.somethingincommon
group by m.somethingincommon;
If you prefer, you can do this with multiple joins:
with s as (
select s.*,
row_number() over (partition by s.somethingincommon order by (select NULL)) as seqnum
from secondtable
)
select m.*, s1.status as status, s2.status as status2, s3.status as status3
from maintable m left join
s s1
on m.somethingincommon = s1.somethingincommon and
s1.seqnum = 1 left join
s s2
on m.somethingincommon = s2.somethingincommon and
s2.seqnum = 2 left join
s s3
on m.somethingincommon = s3.somethingincommon and
s3.seqnum = 3;

left join without duplicate values using MIN()

I have a table_1:
id custno
1 1
2 2
3 3
and a table_2:
id custno qty descr
1 1 10 a
2 1 7 b
3 2 4 c
4 3 7 d
5 1 5 e
6 1 5 f
When I run this query to show the minimum order quantities from every customer:
SELECT DISTINCT table_1.custno,table_2.qty,table_2.descr
FROM table_1
LEFT OUTER JOIN table_2
ON table_1.custno = table_2.custno AND qty = (SELECT MIN(qty) FROM table_2
WHERE table_2.custno = table_1.custno )
Then I get this result:
custno qty descr
1 5 e
1 5 f
2 4 c
3 7 d
Customer 1 appears twice each time with the same minimum qty (& a different description) but I only want to see customer 1 appear once. I don't care if that is the record with 'e' as a description or 'f' as a description.
First of all... I'm not sure why you need to include table_1 in the queries to begin with:
select custno, min(qty) as min_qty
from table_2
group by custno;
But just in case there is other information that you need that wasn't included in the question:
select table_1.custno, ifnull(min(qty),0) as min_qty
from table_1
left outer join table_2
on table_1.custno = table_2.custno
group by table_1.custno;
"Generic" SQL way:
SELECT table_1.custno,table_2.qty,table_2.descr
FROM table_1, table_2
WHERE table_2.id = (SELECT TOP 1 id
FROM table_2
WHERE custno = table_1.custno
ORDER BY qty )
SQL 2008 way (probably faster):
SELECT custno, qty, descr
FROM
(SELECT
custno,
qty,
descr,
ROW_NUMBER() OVER (PARTITION BY custno ORDER BY qty) RowNum
FROM table_2
) A
WHERE RowNum = 1
If you use SQL-Server you could use ROW_NUMBER and a CTE:
WITH CTE AS
(
SELECT table_1.custno,table_2.qty,table_2.descr,
RN = ROW_NUMBER() OVER ( PARTITION BY table_1.custno
Order By table_2.qty ASC)
FROM table_1
LEFT OUTER JOIN table_2
ON table_1.custno = table_2.custno
)
SELECT custno, qty,descr
FROM CTE
WHERE RN = 1
Demolink

Join and a Pivot statement SQL Server

I want to pivot and join to select from 3 tables
Table 1: INT,VARCHAR,FLOAT
ID Name value
---------------------------
1 a1 32116580
2 a2 50785384
3 a3 54327508
4 a4 61030844
Table 2: INT, VARCHAR, FLOAT
ID Name value
---------------------------
1 x11 61326085092
2 x12 80368184260
3 x13 83023398776
4 x14 91144307692
5 x22 95486535484
6 x23 90357090612
7 x24 100588807668
8 x33 707811916752
9 x34 93128452928
10 x44 84566653668
Table 3: INT, VARCHAR, FLOAT
ID Name value
---------------------------
1 q1 61326085092
2 q2 95486535484
3 q3 707811916752
4 q4 84566653668
output table:
column1 column2 column3 column4
--------------------------------------------------------------------------
a1*a1/(q1+q1+x11) a1*a2/(q1+q2+x12) a1*a3/(q1+q3+x13) a1*a4/(q1+q4+x14)
null a2*a2/(q2+q2+x22) a2*a3/(q2+q3+x23) a2*a4/(q2+q4+x24)
null null a3*a3/(q3+q3+x339 a3*a4/(q3+q4+x34)
null null null a4*a4/(q4+q4+x44)
(I'm putting the 'Name' of the column of the 3 different tables instead of numbers)
How to do this?
I guess I have to do two pivots? and
unpivot?...
Well do not how to complete it..
SELECT *
FROM (
SELECT
t1.a1,
t1.a2,
t2.x,
t3.q
FROM table1 t1
INNER JOIN table2 t2
ON t1.id = t2.id
...
) Output
PIVOT (
name IN (
...
PIVOT(name ... )
)
) PivotTable
UPDATE
Previously I have *'s I have changed it to division and sum, the *'s were just an example,
Sample tables
create table Table1(ID int, Name varchar(10), value float)
insert table1 select
1 ,'a1', 32116580 union all select
2 ,'a2', 50785384 union all select
3 ,'a3', 54327508 union all select
4 ,'a4', 61030844
create table Table2(ID int, Name varchar(10), value float)
insert Table2 select
1 ,'x11', 61326085092 union all select
2 ,'x12', 80368184260 union all select
3 ,'x13', 83023398776 union all select
4 ,'x14', 91144307692 union all select
5 ,'x22', 95486535484 union all select
6 ,'x23', 90357090612 union all select
7 ,'x24', 100588807668 union all select
8 ,'x33', 707811916752 union all select
9 ,'x34', 93128452928 union all select
10 ,'x44', 84566653668
create table Table3(ID int, Name varchar(10), value float)
insert Table3 select
1 ,'q1', 61326085092 union all select
2 ,'q2', 95486535484 union all select
3 ,'q3', 707811916752 union all select
4 ,'q4', 84566653668
The query you need, for N = 4. For any other N, just use dynamic SQL to build the query, changing the 2 lines required as indicated by **.
;with coords(i,row,col,total,N) as (
select 1,1,1,N.N*(N.N+1)/2, N.N
from (select count(*) N from table1) N
union all
select i+1,
case when col+1>N then row+1 else row end,
case when col+1>N then row+1 else col+1 end,
total, N
from coords
where i<total
)
select [1],[2],[3],[4] -- **, e.g. ,[5],[6],etc
from
(
select
c.row,
c.col,
cellvalue= ar.value*ac.value/(qr.value+qc.value+x.value)
from coords c
inner join table1 ar on ar.id = c.row
inner join table1 ac on ac.id = c.col
inner join table3 qr on qr.id = c.row
inner join table3 qc on qc.ID = c.col
inner join table2 x on x.ID = c.i
) p
pivot (max(cellvalue) for col in ([1],[2],[3],[4])) pv -- **
order by row
Output:
1 2 3 4
---------------------- ---------------------- ---------------------- ----------------------
5606.50338459295 6876.83326310711 2047.51559459649 8269.17991568225
NULL 9003.55641750708 3087.36780924588 11044.2303130135
NULL NULL 1389.95405212248 3744.35614651666
NULL NULL NULL 14681.7678040306
The dynamic version
declare #Sql nvarchar(max)
select #Sql = ISNULL(#sql + ',', '') + QUOTENAME(RIGHT(number,10))
from master..spt_values
where type='P' and number between 1 and (select COUNT(*) From table1)
set #Sql = '
;with coords(i,row,col,total,N) as (
select 1,1,1,N.N*(N.N+1)/2, N.N
from (select count(*) N from table1) N
union all
select i+1,
case when col+1>N then row+1 else row end,
case when col+1>N then row+1 else col+1 end,
total, N
from coords
where i<total
)
select ' + #sql + '
from
(
select
c.row,
c.col,
cellvalue= ar.value*ac.value/(qr.value+qc.value+x.value)
from coords c
inner join table1 ar on ar.id = c.row
inner join table1 ac on ac.id = c.col
inner join table3 qr on qr.id = c.row
inner join table3 qc on qc.ID = c.col
inner join table2 x on x.ID = c.i
) p
pivot (max(cellvalue) for col in (' + #sql + ')) pv
order by row
option (maxrecursion 0) -- ! use with caution
'
exec(#sql)