Adding rows and changing the row name - sql

I have fetched the values from the sql server database from the following code,
SELECT [Zone Name]
,[Zone Count]
,[Phase Name]
FROM [Interface].[dbo].[VwZoneCount]
where [Zone Name] IN ('EB2GFNMZ','EB2GFSMZ','EB2GFNZ1','EB2GFSZ1','EB21FNZ1','EB21FSMZ','EB2IFSZ1','EB22FNZ1','EB22FSZ1','EB22FSMZ','EB23FNMZ','EB23FNZ1','EB23FNZ2','EB23FNZ3','EB23FSMZ','EB23FSZ1','EB23FSZ2','EB24FNMZ','EB24FNZ1','EB24FSMZ','EB24FSZ1','EB25FNMZ','EB25FNZ1','EB25FSMZ','EB25FSZ1','EB26FNMZ','EB26FNZ1','EB26FSMZ','EB26FSZ1','EB27FNZ1','EB27FSMZ')
GO
The ouput for the above query is ,
Zone Name Zone Count
EB24FNZ1 160
EB24FSMZ 10
EB24FSZ1 87
EB25FNMZ 82
EB25FNZ1 82
EB25FSMZ 12
EB25FSZ1 123
EB26FNMZ 4
EB26FNZ1 92
EB26FSMZ 23
EB26FSZ1 91
EB27FNZ1 1
EB27FSMZ 64
EB2GFNMZ 12
EB2GFNZ1 152
EB2GFSMZ 36
EB2GFSZ1 212
but i need the output by summing some row values .I need to combine values that have 'EB2GFN%' to one with different name,'EB21FN%'..similarly need to combine other rows. Can any body suggest me how i would do that .
Desired output:-
Zone Name Zone Count
EB24F_NORTH_WING 160
EB24F_SOUTH_WING 10+87
EB25F_NORTH_WING 82+82
EB25F_SOUTH_WING 12+123
EB26F_NORTH_WING 4+92
EB26F_SOUTH_WING 23+91
EB27F_NORTH_WING 1
EB27F_SOUTH_WING 64
EB2GF_NORTH_WING 12+152
EB2GF_SOUTH_WING 36+212

You can do this:
;WITH AllZones
AS
(
SELECT * FROM YourQuery
), WithGroupedZones
AS
(
SELECT
ZoneName,
ZoneCount,
LEFT(ZoneName, 2) Eb,
SUBSTRING(ZoneName, 3, 1) EbNumber,
SUBSTRING(ZoneName, 4, 3) F,
SUBSTRING(ZoneName, 8, 1) FNumber
FROM AllZones
)
SELECT
ZoneName,
(SELECT SUM(t2.ZoneCount)
FROM WithGroupedZones t2
WHERE t1.Eb = t2.Eb
AND t1.F = t2.F
AND t1.EBNumber= t2.EBnumber
) ZonesCount
FROM WithGroupedZones t1;
SQL Fiddle Demo
This will give you:
| ZONENAME | ZONESCOUNT |
-------------------------
| EB24FNZ1 | 160 |
| EB24FSMZ | 97 |
| EB24FSZ1 | 97 |
| EB25FNMZ | 164 |
| EB25FNZ1 | 164 |
| EB25FSMZ | 135 |
| EB25FSZ1 | 135 |
| EB26FNMZ | 96 |
| EB26FNZ1 | 96 |
| EB26FSMZ | 114 |
| EB26FSZ1 | 114 |
| EB27FNZ1 | 1 |
| EB27FSMZ | 64 |
| EB2GFNMZ | 164 |
| EB2GFNZ1 | 164 |
| EB2GFSMZ | 248 |
| EB2GFSZ1 | 248 |
Note that: This might be not the same result set that you are looking for. But you can modify the condition, I used in my query:
t1.Eb = t2.Eb
AND t1.F = t2.F
AND t1.EBNumber= t2.EBnumber
To get your desired output. Also note that the zones' names are grouped into:
| ZONENAME | ZONECOUNT | EB | EBNUMBER | F | FNUMBER |
--------------------------------------------------------
| EB24FNZ1 | 160 | EB | 2 | 4FN | 1 |
| EB24FSMZ | 10 | EB | 2 | 4FS | Z |
| EB24FSZ1 | 87 | EB | 2 | 4FS | 1 |
| EB25FNMZ | 82 | EB | 2 | 5FN | Z |
| EB25FNZ1 | 82 | EB | 2 | 5FN | 1 |
| EB25FSMZ | 12 | EB | 2 | 5FS | Z |
| EB25FSZ1 | 123 | EB | 2 | 5FS | 1 |
| EB26FNMZ | 4 | EB | 2 | 6FN | Z |
| EB26FNZ1 | 92 | EB | 2 | 6FN | 1 |
| EB26FSMZ | 23 | EB | 2 | 6FS | Z |
| EB26FSZ1 | 91 | EB | 2 | 6FS | 1 |
| EB27FNZ1 | 1 | EB | 2 | 7FN | 1 |
| EB27FSMZ | 64 | EB | 2 | 7FS | Z |
| EB2GFNMZ | 12 | EB | 2 | GFN | Z |
| EB2GFNZ1 | 152 | EB | 2 | GFN | 1 |
| EB2GFSMZ | 36 | EB | 2 | GFS | Z |
| EB2GFSZ1 | 212 | EB | 2 | GFS | 1 |
Then you can compare the ZoneName using these groups EB, EBNUMBER, F, FNUMBER

Try this, it will give you sums for groups that have first 6 letters in common:
SELECT LEFT(Zone_Prefix, 5) + CASE WHEN RIGHT(Zone_Prefix, 1) = 'N' THEN '_NORTH_WING' ELSE '_SOUTH_WING' END AS [Zone Name],
Cnt AS [Zone Count]
FROM
(
SELECT LEFT([Zone Name], 6) AS Zone_Prefix
,SUM([Zone Count]) Cnt
FROM [Interface].[dbo].[VwZoneCount]
WHERE [Zone Name] IN ('EB2GFNMZ','EB2GFSMZ','EB2GFNZ1','EB2GFSZ1','EB21FNZ1','EB21FSMZ','EB2IFSZ1','EB22FNZ1','EB22FSZ1','EB22FSMZ','EB23FNMZ','EB23FNZ1','EB23FNZ2','EB23FNZ3','EB23FSMZ','EB23FSZ1','EB23FSZ2','EB24FNMZ','EB24FNZ1','EB24FSMZ','EB24FSZ1','EB25FNMZ','EB25FNZ1','EB25FSMZ','EB25FSZ1','EB26FNMZ','EB26FNZ1','EB26FSMZ','EB26FSZ1','EB27FNZ1','EB27FSMZ')
GROUP BY
LEFT([Zone Name], 6)
) tbl
Here is an SQL Fiddle

Related

How to determine top x rows with a group by - SQL Server 2017

I have a dataset that looks like the following:
| Category | Employee | Output |
|:--------:|:--------:|:------:|
| Top | A | 97 |
| Mid | B | 50 |
| Mid | C | 35 |
| Mid | D | 45 |
| Low | E | 15 |
| Low | F | 16 |
| Top | G | 92 |
| Top | H | 84 |
| Mid | I | 49 |
| Mid | J | 31 |
| Low | K | 22 |
| Top | L | 79 |
| Mid | M | 63 |
| Mid | N | 33 |
| Low | O | 19 |
| Mid | P | 33 |
| Top | Q | 77 |
| Top | R | 88 |
| Low | S | 30 |
| Mid | T | 53 |
| Mid | U | 68 |
| Mid | V | 72 |
| Mid | W | 66 |
| Mid | X | 51 |
| Mid | Y | 35 |
| Mid | Z | 70 |
(The real dataset is much larger, about ~20K Rows)
I am trying to find the top 3 output numbers for each group. Ultimately resulting in a dataset like:
| Low | 30 |
|:---:|:--:|
| Low | 22 |
| Low | 19 |
| Mid | 72 |
| Mid | 70 |
| Mid | 68 |
| Top | 97 |
| Top | 92 |
| Top | 88 |
I have tried:
SELECT TOP 10
Category,
Output
FROM
raw_data
ORDER BY
Output DESC
But that only lists the top 10 overall, not by category.
Adding
GROUP BY Category, Count_Placements obviously does nothing, and I cannot group by Category itself.
Sorry there is no SQL Fiddle like I normally do, it is currently down.
You can use row_number():
select category, output
from (
select t.*, row_number() over(partition by category order by output desc) rn
from mytable t
) t
where rn <= 3
order by category, output desc

Segregate rows according to their HEAD (parent) - sql

I have the following SQL table.
+----+--------+----------+--------+
| ID | TestNo | TestName | HeadID |
+----+--------+----------+--------+
| 1 | 21 | Comp-1 | null |
| 2 | 22 | C1 | 21 |
| 3 | 23 | C2 | 21 |
| 4 | 24 | C3 | 21 |
| 5 | 47 | Comp-2 | null |
| 6 | 25 | C4 | 47 |
| 7 | 26 | C1+ | 21 |
+----+--------+----------+--------+
I want to get all the child rows (according to their HeadID) below their head test.
select * from ranges order by HeadID
The ACTUAL OUPUT I get from the above query:
+----+--------+----------+--------+
| ID | TestNo | TestName | HeadID |
+----+--------+----------+--------+
| 1 | 21 | Comp-1 | null |
| 5 | 47 | Comp-2 | null |
| 2 | 22 | C1 | 21 |
| 3 | 23 | C2 | 21 |
| 4 | 24 | C3 | 21 |
| 7 | 26 | C1+ | 21 |
| 6 | 25 | C4 | 47 |
+----+--------+----------+--------+
but my DESIRED OUTPUT is:
+----+--------+----------+--------+
| ID | TestNo | TestName | HeadID |
+----+--------+----------+--------+
| 1 | 21 | Comp-1 | null |
| 2 | 22 | C1 | 21 |
| 3 | 23 | C2 | 21 |
| 4 | 24 | C3 | 21 |
| 7 | 26 | C1+ | 21 |
| 5 | 47 | Comp-2 | null |
| 6 | 25 | C4 | 47 |
+----+--------+----------+--------+
How can I achieve this?
If you have only one level of children, then you can achieve this ordering like this:
SELECT *
FROM Ranges
ORDER BY
CASE WHEN HeadID IS NULL THEN TestNo ELSE HeadID END
,HeadID
,ID
;

select all rows that match criteria if not get a random one

+----+---------------+--------------------+------------+----------+-----------------+
| id | restaurant_id | filename | is_profile | priority | show_in_profile |
+----+---------------+--------------------+------------+----------+-----------------+
| 40 | 20 | 1320849687_390.jpg | | | 1 |
| 60 | 24 | 1320853501_121.png | 1 | | 1 |
| 61 | 24 | 1320853504_847.png | | | 1 |
| 62 | 24 | 1320853505_732.png | | | 1 |
| 63 | 24 | 1320853505_865.png | | | 1 |
| 64 | 29 | 1320854617_311.png | 1 | | 1 |
| 65 | 29 | 1320854617_669.png | | | 1 |
| 66 | 29 | 1320854618_636.png | | | 1 |
| 67 | 29 | 1320854619_791.png | | | 1 |
| 74 | 154 | 1320922653_259.png | | | 1 |
| 76 | 154 | 1320922656_332.png | | | 1 |
| 77 | 154 | 1320922657_106.png | | | 1 |
| 84 | 130 | 1321269380_960.jpg | 1 | | 1 |
| 85 | 130 | 1321269383_555.jpg | | | 1 |
| 86 | 130 | 1321269384_251.jpg | | | 1 |
| 89 | 28 | 1321269714_303.jpg | | | 1 |
| 90 | 28 | 1321269716_938.jpg | 1 | | 1 |
| 91 | 28 | 1321269717_147.jpg | | | 1 |
| 92 | 28 | 1321269717_774.jpg | | | 1 |
| 93 | 28 | 1321269717_250.jpg | | | 1 |
| 94 | 28 | 1321269718_964.jpg | | | 1 |
| 95 | 28 | 1321269719_830.jpg | | | 1 |
| 96 | 43 | 1321270013_629.jpg | 1 | | 1 |
+----+---------------+--------------------+------------+----------+-----------------+
I have this table and I want to select the filename for a given list of restaurants ids.
For example for 24,29,154:
+----+---------------
| filename |
+----+---------------
1320853501_121.png (has is_profile 1)
1320854617_311.png (has is_profile 1)
1320922653_259.png (chosen as profile picture because restaurant doesn't have a profile pic but has pictures)
I tried group by and case statements but I got nowhere.Also if you use group by it should be a full group by.
You can do this with aggregation and some logic:
select restaurant_id,
coalesce(max(case when is_profile = 1 then filename end),
max(filename)
) as filename
from t
where restaurant_id in (24, 29, 154)
group by restaurant_id;
First look for the/a profile filename. Next just choose an arbitrary one.

Oracle SQL: getting all row maximum number from specific multiple criteria

I have the following table named foo:
ID | D1 | D2 | D3 |
---------------------
1 | 47 | 3 | 71 |
2 | 47 | 98 | 82 |
3 | 0 | 99 | 3 |
4 | 3 | 100 | 6 |
5 | 48 | 10 | 3 |
6 | 49 | 12 | 4 |
I want to run a select query and have the results show like this
ID | D1 | D2 | D3 | Result |
------------------------------
1 | 47 | 3 | 71 | D3 |
2 | 47 | 98 | 82 | D2 |
3 | 0 | 99 | 3 | D2 |
4 | 3 | 100 | 6 | D2 |
5 | 48 | 10 | 3 | D1 |
6 | 49 | 12 | 4 | D1 |
So, basically I want to get Maximum value between D1, D2, D3 column divided by id.
As You may seen , ID 1 have D3 in the Result column since Maximum value between
D1 : D2 : D3
That Means 4 : 3 : 71 , Max value is 71. Thats Why The Result show 'D3'
Is there a way to do this in a sql query ?
Thanks!
For Oracle please try this one
select foo.*, case when greatest(d1, d2, d3) = d1 then 'D1'
when greatest(d1, d2, d3) = d2 then 'D2'
when greatest(d1, d2, d3) = d3 then 'D3'
end result
from foo
Consider the following - a normalized approach...
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table
(id INT NOT NULL
,d INT NOT NULL
,val INT NOT NULL
,PRIMARY KEY(id,d)
);
INSERT INTO my_table VALUES
(1,1,47),
(2,1,47),
(3,1,0),
(4,1,3),
(5,1,48),
(6,1,49),
(1,2,3),
(2,2,98),
(3,2,99),
(4,2,100),
(5,2,10),
(6,2,12),
(1,3,71),
(2,3,82),
(3,3,3),
(4,3,6),
(5,3,3),
(6,3,4);
SELECT * FROM my_table;
+----+---+-----+
| id | d | val |
+----+---+-----+
| 1 | 1 | 47 |
| 1 | 2 | 3 |
| 1 | 3 | 71 |
| 2 | 1 | 47 |
| 2 | 2 | 98 |
| 2 | 3 | 82 |
| 3 | 1 | 0 |
| 3 | 2 | 99 |
| 3 | 3 | 3 |
| 4 | 1 | 3 |
| 4 | 2 | 100 |
| 4 | 3 | 6 |
| 5 | 1 | 48 |
| 5 | 2 | 10 |
| 5 | 3 | 3 |
| 6 | 1 | 49 |
| 6 | 2 | 12 |
| 6 | 3 | 4 |
+----+---+-----+
SELECT x.*
FROM my_table x
JOIN
( SELECT id,MAX(val) max_val FROM my_table GROUP BY id) y
ON y.id = x.id
AND y.max_val = x.val;
+----+---+-----+
| id | d | val |
+----+---+-----+
| 1 | 3 | 71 |
| 2 | 2 | 98 |
| 3 | 2 | 99 |
| 4 | 2 | 100 |
| 5 | 1 | 48 |
| 6 | 1 | 49 |
+----+---+-----+
(This is intended as a MySQL solution - I'm not familiar with ORACLE syntax, so apologies if this doesn't port)
Does this answer your comment?
SELECT x.* , y.max_val
FROM my_table x
JOIN
( SELECT id,MAX(val) max_val FROM my_table GROUP BY id) y
ON y.id = x.id ;
+----+---+-----+---------+
| id | d | val | max_val |
+----+---+-----+---------+
| 1 | 1 | 47 | 71 |
| 1 | 2 | 3 | 71 |
| 1 | 3 | 71 | 71 |
| 2 | 1 | 47 | 98 |
| 2 | 2 | 98 | 98 |
| 2 | 3 | 82 | 98 |
| 3 | 1 | 0 | 99 |
| 3 | 2 | 99 | 99 |
| 3 | 3 | 3 | 99 |
| 4 | 1 | 3 | 100 |
| 4 | 2 | 100 | 100 |
| 4 | 3 | 6 | 100 |
| 5 | 1 | 48 | 48 |
| 5 | 2 | 10 | 48 |
| 5 | 3 | 3 | 48 |
| 6 | 1 | 49 | 49 |
| 6 | 2 | 12 | 49 |
| 6 | 3 | 4 | 49 |
+----+---+-----+---------+

SQL Group Results and Add them up based on product

I've got the following SQL which basically works out the costings etc for each item.
SELECT
L.LocID,
L.LocationName,
L.LocationSqrMtr,
L.LocationAddress,
L.LocationPostCode,
L.LocationContact,
I.SubPIDItemID,
I.SPID,
I.ProductID,
C.SubPIDCostID,
C.PricePerItem,
C.ManDayPerItem
FROM
dbo.SubPIDCosts AS C
INNER JOIN dbo.SubPIDItems AS I ON
C.ProductID = I.ProductID
RIGHT OUTER JOIN dbo.SubPIDLocations AS L ON
I.LocationID = L.LocID AND C.LocationID = L.LocID
WHERE C.SPID = 48
This returns:
+-------+--------------+----------------+-----------------+------------------+-----------------+--------------+----------+-----------+--------------+--------------+---------------+-----+----+---+-----+--------+--------+--------+------+
| LocID | LocationName | LocationSqrMtr | LocationAddress | LocationPostCode | LocationContact | SubPIDItemID | SPID | ProductID | SubPIDCostID | PricePerItem | ManDayPerItem | | | | | | | | |
+-------+--------------+----------------+-----------------+------------------+-----------------+--------------+----------+-----------+--------------+--------------+---------------+-----+----+---+-----+--------+--------+--------+------+
| 379 | | | Location | 1 | 1 | 345 | Generic | Building | Generic | Building | NULL | 158 | 48 | | | | 108 | 0.3400 | 6.17 |
| 379 | | | Location | 1 | 1 | 345 | Generic | Building | Generic | Building | NULL | 159 | 48 | 1 | 109 | 0.3400 | | .47 | |
| 379 | 3 | Location | 1 | 615 | Generic | Building | Generic | Building | NULL | 160 | 48 | | | | 110 | 0.7317 | 0.50 | | |
| 379 | 4 | Location | | | 615 | Generic | Building | Generic | Building | NULL | 161 | 48 | | | | 111 | 0.7317 | 0.50 | |
| 379 | 4 | Location | | | 615 | Generic | Building | Generic | Building | NULL | 16 | | 48 | 1 | 11 | | 0.7317 | 0.50 | |
+-------+--------------+----------------+-----------------+------------------+-----------------+--------------+----------+-----------+--------------+--------------+---------------+-----+----+---+-----+--------+--------+--------+------+
But what I would like to do is group it by the product ID. So all the ones that are ProductID 22 it should add the values up for ManDayPerItem and PricePerItem and LocationSqrMtr
It's used in the following context
I'd like to have them grouped nicely in that list.
As you said, group by:
SELECT ProductID, SUM(ManDayPerItem), SUM(PricePerItem), SUM(LocationSqrMtr)
FROM
dbo.SubPIDCosts AS C
INNER JOIN dbo.SubPIDItems AS I ON
C.ProductID = I.ProductID
RIGHT OUTER JOIN dbo.SubPIDLocations AS L ON
I.LocationID = L.LocID AND C.LocationID = L.LocID
WHERE C.SPID = 48
GROUP BY ProductID;