SQL join rows into one - sql

| fk | red | brown | green |
|1337| 1 | 0 | 0 |
|1337| 0 | 1 | 0 |
|1337| 0 | 0 | 1 |
In tSql how would i return these as one row to say that 1337 has been red, brown and green at some point?
| fk | red | brown | green |
|1337| 1 | 1 | 1 |

Using Max function Grouping by fk
select fk, max(red) red, max(brown) brown, max(green) green
from yourTable
group by fk
If red, brown & green are bit type fields then try as below
select fk, max(red+0) red, max(brown+0) brown, max(green+0) green
from yourTable
group by fk

By grouping :
Select fk ,
Max(red) as red,
Max(brown) as brown,
Max(green) as green
FROM myTableName
GROUP BY fk

Like so:
SELECT fk
,MAX(red)
,MAX(brown)
,MAX(green)
FROM yourtable
GROUP BY fk

Related

Check box like functionality in table using query in SQL Server

I have a primary table with multiple records for the name but different quantity and colors.
TblPrimary: current table
id | name | color | Quan |
===+=========+=======+=======+
1 | Apple | Red | 10 |
2 | Banana | Yellow| 5 |
3 | Mango | Yellow| 8 |
4 | Apple | Green | 20 |
5 | Banana | Brown | 15 |
6 | Mango | Orange| 12 |
7 | Mango | Green | 5 |
This is my main table and I basically want data from the primary table like this. So basically the Quan in main table is sum of all individual Quan from the primary table. The colors (Red,Yellow,Brown) in the main table; are bits which indicate whether that color is present for the fruit or not in the primary table.
TblMain: new expected table
id | Name | Quan | Red | Yellow | Brown | Green | Orange |
===+=========+=======+=====+========+=======+=======+========+
1 | Apple | 30 | 1 | 0 | 0 | 1 | 0 |
2 | Banana | 20 | 0 | 1 | 1 | 0 | 0 |
3 | Mango | 25 | 0 | 1 | 0 | 1 | 1 |
I have got the below query and I have group by and the sum. I am not able to get the colors portion of the main table populated.
INSERT INTO TblMain(Name, Quan)
(SELECT Name, SUM(Quan)
FROM TblPrimary
GROUP BY Name)
You can try to use sum windows function in subquery then use condition aggregate function make your expect result.
select ROW_NUMBER() OVER(ORDER BY name) id,
name,
Quan,
SUM(CASE WHEN color = 'Red' THEN 1 ELSE 0 END) 'Red',
SUM(CASE WHEN color = 'Yellow' THEN 1 ELSE 0 END) 'Yellow',
SUM(CASE WHEN color = 'Brown' THEN 1 ELSE 0 END) 'Brown',
SUM(CASE WHEN color = 'Green' THEN 1 ELSE 0 END) 'Green',
SUM(CASE WHEN color = 'Orange' THEN 1 ELSE 0 END) 'Orange'
from (
SELECT name,
color,
SUM(Quan) OVER(PARTITION BY name ORDER BY name) Quan
FROM TblPrimary
) t1
group by name,Quan
sqlfiddle
Result
id name Quan Red Yellow Brown Green Orange
1 Apple 30 1 0 0 1 0
2 Banana 20 0 1 1 0 0
3 Mango 25 0 1 0 1 1
You can use PIVOT to convert values to columns. In your case this becomes a bit cumbersome, because you want the row sum as well as well as the 0/1 flags
SELECT
name,
ISNULL(Red,0) + ISNULL(Yellow,0) + ISNULL(Brown,0) + ISNULL(Green,0) + ISNULL(Orange,0) As Quan,
CASE WHEN Red IS NULL THEN 0 ELSE 1 END AS Red,
CASE WHEN Yellow IS NULL THEN 0 ELSE 1 END AS Yellow,
CASE WHEN Brown IS NULL THEN 0 ELSE 1 END AS Brown,
CASE WHEN Green IS NULL THEN 0 ELSE 1 END AS Green,
CASE WHEN Orange IS NULL THEN 0 ELSE 1 END AS Orange
FROM
(SELECT name, color, Quan
FROM dbo.TblPrimary) AS SourceTable
PIVOT
(
SUM(Quan)
FOR color IN (Red, Yellow, Brown, Green, Orange)
) AS PivotTable;
If you display the sums directly for the colors instead of the flags, the query simplifies to:
SELECT
name, Red, Yellow, Brown, Green, Orange
FROM
(SELECT name, color, Quan
FROM dbo.TblPrimary) AS SourceTable
PIVOT
(
SUM(Quan)
FOR color IN (Red, Yellow, Brown, Green, Orange)
) AS PivotTable;
And the result will be:
name Red Yellow Brown Green Orange
==========================================
Apple 10 null null 20 null
Banana null 5 15 null null
Mango null 8 null 5 12

Count percentage of certain column values and add it to a new column

I have a following table
[Table_OrangeIsNewBlack]
ID | Name | Color | RedPercent
------------------------------------------
1 | Donald | Orange |
2 | Hillary | White |
3 | Barack | Black |
4 | Bernie | Grey |
1 | Donald | Red |
2 | Hillary | Red |
3 | Barack | Black |
4 | Bernie | Grey |
1 | Donald | Red |
2 | Hillary | Blue |
3 | Barack | Red |
4 | Bernie | Purple |
I need to add a percentage value presenting how often person is 'Red'
Donald's record
1 Donald Orange
1 Donald Red
1 Donald Red
RedPercent : (2 / 3 ) * 100 = 66,66
Hillary
2 Hillary White
2 Hillary Red
2 Hillary Blue
'Blue' and 'Purple' do not count, thus :
RedPercent : (1 / 2) * 100 = 50,00
Barack
3 Barack Black
3 Barack Black
3 Barack Red
RedPercent : (1 / 3) * 100 = 33,33
Bernie
4 Bernie Grey
4 Bernie Blue
4 Bernie Purple
'Blue' and 'Purple' do not count
RedPercent : (0 / 1) * 100 = 00,00
Result needed:
[Table_OrangeIsNewBlack]
ID | Name | Color | RedPercent
------------------------------------------
1 | Donald | Orange | 66,66
2 | Hillary | White | 50,00
3 | Barack | Black | 33,33
4 | Bernie | Grey | 00,00
1 | Donald | Red | 66,66
2 | Hillary | Red | 50,00
3 | Barack | Black | 33,33
4 | Bernie | Grey | 00,00
1 | Donald | Red | 66,66
2 | Hillary | Blue | 50,00
3 | Barack | Red | 33,33
4 | Bernie | Purple | 00,00
I've tried :
;WITH CTE AS
(
SELECT ID,
-- Division: count of Reds / count of persons all rows
((SELECT COUNT(ID) FROM Table_OrangeIsNewBlack
WHERE Color = 'Red' )
/
(SELECT COUNT(ID) FROM Table_OrangeIsNewBlack
WHERE ( Color <> 'Blue' and
Color <> 'Purple' ))
)
AS redprcnt
-- end of Division
FROM Table_OrangeIsNewBlack
)
UPDATE T1
SET RedPercent = CTE.redprcnt
FROM Table_OrangeIsNewBlack T1
INNER JOIN CTE ON(T1.ID = CTE.ID)
SELECT clause...
SELECT ID,
-- Division: count of Reds / count of persons all rows
((SELECT COUNT(ID) FROM Table_OrangeIsNewBlack
WHERE Color = 'Red' )
/
(SELECT COUNT(ID) FROM Table_OrangeIsNewBlack
WHERE ( Color <> 'Blue' and
Color <> 'Purple' ))
)
AS redprcnt
-- end of Division
FROM Table_OrangeIsNewBlack
...gives only zeros for redprcnt
Should i use GROUP BY at some point?
Any suggestions?
Thanks in advance.
COUNT usually results in a INTEGER, thus COUNT/COUNT is an integer division which truncates and your base query tries to calculate the overall percentage instead of the % per group.
Additionally your calculation can be simplified using conditional aggregation:
SELECT ID,
-- Division: count of Reds / count of persons all rows
100.00 * COUNT(CASE WHEN Color = 'Red' THEN ID END)
/ NULLIF(COUNT(CASE WHEN Color <> 'Blue' and Color <> 'Purple' THEN ID END), 0) AS redprcnt
FROM Table_OrangeIsNewBlack
GROUP BY ID
The CASE returns NULL for non-matching rows which are not counted.
Edit:
If you actually need to repeat the percentage for each row you can switch to a Windowed Aggregate instead:
SELECT ID, Name, Color,
100.00 * Count(CASE WHEN Color = 'Red' THEN ID END) Over(PARTITION BY NAME)
/ NULLIF(Count(CASE WHEN Color <> 'Blue' AND Color <> 'Purple' THEN ID END) Over(PARTITION BY NAME), 0) AS redprcnt
FROM Table_OrangeIsNewBlack
Interesting Task, I have made script that may help you
;WITH CTE AS
(
SELECT * ,COUNT(CASE WHEN Color = 'Red' THEN ID END) OVER(Partition by Name,Color) ColorCount,
COUNT(CASE WHEN Color <> 'Blue' and Color <> 'Purple' THEN ID END) OVER(Partition by Name)TotalCount
FROM TableName
)
SELECT ID,Name, (SELECT MAX(((ColorCount*1.0)/(CASE WHEN TotalCount = 0 THEN 1 ELSE TotalCount END))*100)
FROM CTE InnerCte
WHERE OuterCTE.ID=InnerCte.ID AND OuterCTE.Name=InnerCte.Name )
FROM CTE OuterCTE

Oracle SQL Query for Stacked Pareto Chart

I have an Oracle Table that contains data similar to the following basic example:
+--------+----------+
| SERIES | CATEGORY |
+--------+----------+
| green | apple |
| green | pear |
| green | pear |
| yellow | apple |
| yellow | apple |
| yellow | pear |
| yellow | pear |
| yellow | pear |
| yellow | banana |
| yellow | banana |
| yellow | banana |
| red | apple |
+--------+----------+
I would like to generate a Pareto-like Graph of this data that should look as like Stacked Pareto Chart,
To create this graph I would like to run a SQL query and get the following output:
+----------+--------+-------+
| CATEGORY | SERIES | COUNT |
+----------+--------+-------+
| pear | green | 2 |
| pear | yellow | 3 |
| apple | green | 1 |
| apple | yellow | 2 |
| apple | red | 1 |
| banana | yellow | 3 |
+----------+--------+-------+
The actual table has millions of entries and it currently takes a significant amount of time to query the database as the current procedure I am using is not very efficient:
Order the categories by the amount of entries in each category:
SELECT CATEGORY, COUNT(CATEGORY) FROM FRUIT GROUP BY CATEGORY ORDER BY COUNT(CATEGORY);
Then for each category I list the relevant series in order of the series:
SELECT SERIES, COUNT(SERIES) FROM FRUIT WHERE CATEGORY = [current category] GROUP BY SERIES ORDER BY SERIES;
What would be the most efficient way to query the database (Preferably a single SQL statement) in order to get the desired output?
Some shorter version:
select category, series, CntS
from (
select distinct count(category) over (partition by category) cntC,
count(series) over (partition by category, series ) cntS,
category, series
from fruit ) Tab
order by CntC desc, cntS desc;
You can achieve the desired result by grouping on both CATEGORY and SERIES:
SELECT
CATEGORY, SERIES, COUNT(*)
FROM FRUIT
GROUP BY CATEGORY, SERIES
ORDER BY COUNT(*);
UPDATE:
To order by total of CATEGORY first and then green, yellow, red, just like your expected output:
SELECT t1.*
FROM (
SELECT
CATEGORY, SERIES, COUNT(*) AS CNT
FROM FRUIT
GROUP BY CATEGORY, SERIES
) t1
INNER JOIN (
SELECT
CATEGORY, COUNT(*) AS CNT
FROM FRUIT
GROUP BY CATEGORY
) t2
ON t1.CATEGORY = t2.CATEGORY
ORDER BY
t2.CNT DESC,
CASE t1.SERIES
WHEN 'green' THEN 1
WHEN 'yellow' THEN 2
WHEN 'red' THEN 3
END

SQL Count: How to count value of a column from the same value of other column

Sorry about the title.
Sample:
I have this table(tblTry):
id | Name | Color
____________________
1 | XYZ | Black
2 | XYZ | Black
3 | ASD | Red
4 | ASD | White
5 | ASD | White
And this is the output I want:
Name | Black | Red | White
__________________________
XYZ | 2 | 0 | 0
ASD | 0 | 1 | 2
I have this sql but it gives me different output:
select distinct
Name,
(select count(*) from tblTry where Color= 'Black') as Black,
(select count(*) from tblTry where Color= 'Red') as Red,
(select count(*) from tblTry where Color= 'White') as White,
from tblTry
group by Name
sql above output:
__________________________
Name | Black | Red | White
__________________________
XYZ | 2 | 1 | 2
ASD | 2 | 1 | 2
Can anyone help me?
Thanks
This is a pivot, which has several solutions. One that is general across databases is to use conditional aggregation:
select name,
sum(case when Color = 'Black' then 1 else 0 end) as Black,
sum(case when Color = 'Red' then 1 else 0 end) as Red,
sum(case when Color = 'White' then 1 else 0 end) as White
from tblTry
group by name;
The problem with your query is that the counts need to be correlated to each row. You would do this with an additional where condition:
(select count(*) from tblTry t2 where t2.Color= 'Black' and t2.name = tblTry.name) as Black,

Transpose Microsoft SQL Server table [duplicate]

This question already has answers here:
Simple way to transpose columns and rows in SQL?
(9 answers)
Closed 8 years ago.
I have two tables, a header table and a detail table. The data looks like this:
OBJ_NO | Name
12345 | Fred
67891 | Bob
Detail table:
OBJ_NO | HEADER_OBJ_NO | CODE
1 | 12345 | Red
2 | 12345 | Blue
3 | 12345 | Green
4 | 67891 | Red
5 | 67781 | Green
Essentially what I am after is to see something like this:
OBJ_NO | Name | Red | Blue | Green
12345 | Fred | 1 | 1 | 1
67891 | Bob | 1 | 0 | 1
It could be different number of "Colours" as well. Its not set. And not each Header Ref would have one of each colour as shown in the example above.
How would I achieve this?
A SQL Server PIVOT will work for you.
WITH CTE(OBJ_NO, NAME, RED, BLUE, GREEN)
AS
(
SELECT [OBJ_NO]
,[NAME]
,[red],[blue],[green]
FROM (SELECT T2.[OBJ_NO]
,T2.[NAME], T1.CODE FROM [dbo].[Table_2] T2
INNER JOIN [dbo].[Table_1] T1 ON T1.HEADER_OBJ_NO = T2.OBJ_NO ) AS SourceTable
PIVOT
(MAX(CODE)
FOR CODE IN ([red], [blue], [green])
)AS PivotTable
)
SELECT OBJ_NO
,NAME
,RED = CASE WHEN RED = 'red' THEN 1 ELSE 0 END
,BLUE = CASE WHEN BLUE = 'blue' THEN 1 ELSE 0 END
,GREEN = CASE WHEN GREEN = 'green' THEN 1 ELSE 0 END
FROM CTE