Flatten SQL for 4 tables - sql-server

In SQL Server 2012, I have four tables that look like:
Issues:
IssueID | IssueTitle
1 | Light Bulb Burnt Out
2 | Thermostat not working
LocationTypes:
TypeID | Type
1 | Building
2 | Floor
3 | Room
Locations:
LocaltionID | TypeID | Location | ParentLocation
0 | 1 | default | 0
1 | 1 | Sears Tower | 0
2 | 1 | IDS | 0
3 | 2 | Floor 1 | 1
4 | 2 | Floor 2 | 1
5 | 2 | Floor 3 | 1
6 | 2 | Floor 4 | 1
7 | 2 | Floor 5 | 1
8 | 2 | Floor 6 | 1
9 | 2 | Floor 7 | 1
10 | 2 | Floor 8 | 1
108 | 3 | Room 101 | 3
109 | 3 | Room 102 | 3
110 | 3 | Room 110 | 3
111 | 3 | Room 202 | 4
112 | 3 | Room 300 | 5
175 | 2 | 1st Floor | 2
185 | 2 | 2nd Floor | 2
186 | 3 | Suite 295 | 185
IssueLocations:
IssueID | LocationId
1 | 1
1 | 5
1 | 112
2 | 2
2 | 185
And what I want to do is combine the tables so that I end up with one row for each issuer, with field names as column headers and the field values, so I end up with:
Result:
IssueID | IssueTitle | Building | Floor | Room
--------------------------------------------------------------------------
1 | Light Bulb Burnt Out | Sears Tower | Floor 1 | Room 300
2 | Thermostat not working | IDS | 2nd Floor |
Notice the second issue doesn't have a room (no locations are required), location less issues are valid. Note other constraints might cause a required location but I don't think that is not relevant for this question.

You need to use Pivot to transpose your rows to columns.
SQL FIDDLE DEMO
SELECT *
FROM (SELECT il.IssueID,
l.Location,
i.IssueTitle,
lt.Type
FROM Locations l
JOIN LocationTypes lt
ON l.TypeID = lt.TypeID
JOIN IssueLocations il
ON il.LocationId = l.LocaltionID
JOIN issues i
ON i.IssueID = il.IssueID) a
PIVOT (Max(location)
FOR type IN([Building],
[Floor],
[Room]))piv

Related

How to check a specific range value is filled in SQL with Window functions?

I am working on a project in which we should evaluate suppliers and in this database I have this table EvaluationGrade:
+------+---------------------+------------+-----------+
| Id | EvaluationMethodId | FromScore | ToScore |
+------+---------------------+------------+-----------+
| 1 | 2 | 1 | 20 |
| 2 | 2 | 21 | 50 |
| 3 | 2 | 51 | 70 |
| 4 | 2 | 71 | 100 |
| 5 | 3 | 1 | 20 |
| 6 | 3 | 31 | 40 |
+------+---------------------+------------+-----------+
This table categorize scores and I am gonna be sure for EvaluationMethodId=2 scope values fill 1 to 100 (just like sample above).
I am looking for something like this:
+---------------------+------------+
| EvaluationMethodId | Sum |
+---------------------+------------+
| 2 | 100 |
| 3 | 30 |
+---------------------+------------+
This is the way I attempted:
WITH myUpdate
AS (SELECT emg.Id,emg.EvaluationMethodId,
SUM(emg.ToGrade - emg.FromGrade) + 1 AS SumScope
FROM generalsup.EvaluationMethodGrading emg
GROUP BY emg.Id,emg.EvaluationMethodId)
SELECT myUpdate.EvaluationMethodId, SUM(myUpdate.SumScope) AS SumScopeAll
FROM myUpdate
GROUP BY myUpdate.EvaluationMethodId;
But I use window function that put less overhead on server.
Since there is no case of overlaps in the scores, you can do it with group by EvaluationMethodId and sum():
select EvaluationMethodId, sum(ToScore - FromScore + 1) [Sum]
from EvaluationMethodGrading
group by EvaluationMethodId
See the demo.
Results:
> EvaluationMethodId | Sum
> -----------------: | --:
> 2 | 100
> 3 | 30

How to make a pivot table in DB2?

I have a table be like:
| Date | Week | Name | No | Count |
|-----------|------|--------|----|-------|
| 2019/4/1 | 14 | John | 1 | 1 |
| 2019/4/1 | 14 | Mary | 2 | 1 |
| 2019/4/9 | 15 | Kevin | 3 | 2 |
| 2019/4/9 | 15 | John | 4 | 1 |
| 2019/4/9 | 15 | Jessie | 5 | 1 |
| 2019/4/18 | 16 | Kevin | 6 | 1 |
| 2019/4/18 | 16 | John | 7 | 1 |
| 2019/4/18 | 16 | Jessie | 8 | 2 |
| 2019/4/18 | 16 | Mary | 9 | 3 |
| 2019/4/18 | 16 | Mary | 10 | 1 |
| 2019/4/18 | 16 | Jessie | 11 | 1 |
| 2019/4/24 | 17 | Mary | 12 | 1 |
| 2019/4/24 | 17 | Jessie | 13 | 1 |
What I want to do is to calculate people's total count per Week.
And sort by their total count.
I know GROUP BY can make this happen, I've tried, but just can't figure it out.
This is what I expect:
| Name | 14 | 15 | 16 | 17 | Total |
|--------|----|----|----|----|-------|
| Mary | 1 | 0 | 4 | 1 | 6 |
| Jessie | 0 | 1 | 3 | 1 | 5 |
| John | 1 | 1 | 1 | 0 | 3 |
| Kevin | 0 | 2 | 1 | 0 | 3 |
| Total | 2 | 4 | 9 | 2 | 17 |
How can I do?
Select [Name]
,sum(case when [Week] = 14 then [Count] else 0 end) as Week14
,sum(case when [Week] = 15 then [Count] else 0 end) as Week15
,sum(case when [Week] = 16 then [Count] else 0 end) as Week16
,sum(case when [Week] = 17 then [Count] else 0 end) as Week17
,sum([Count]) as Total
from [table]
group by [Name]
order by Total
I'm not sure which version of DB2 you're using (LUW/zOS/i) so this is a general answer. The week number can be made to be more flexible but a certain amount of hard coding will need to be done for the number of weeks.

Can't build click house query

I have a click house table like this:
page_id ad_id date
-------|-------|------------|
1 | 10 | 04/03/2009 |
1 | 2 | 04/03/2009 |
1 | 2 | 04/03/2009 |
1 | 4 | 04/03/2009 |
1 | 2 | 04/03/2009 |
2 | 1 | 04/03/2009 |
2 | 5 | 04/03/2009 |
3 | 2 | 04/03/2009 |
3 | 2 | 04/03/2009 |
3 | 2 | 04/03/2009 |
3 | 8 | 04/03/2009 |
4 | 1 | 04/03/2009 |
4 | 1 | 04/03/2009 |
5 | 2 | 04/03/2009 |
This table contains the history of clicks on different ad-blocks on different pages. Just a big log. I want to get top ads with hits count for each page. Smthing like
page_id ad_id hits
-------|-------|------------|
1 | 2 | 3 |
2 | 1 | 1 |
3 | 2 | 3 |
4 | 1 | 2 |
5 | 2 | 1 |
Hope somebody can help me. Thanks.
Try this:
SELECT page_id, ad_id, count() cnt
FROM TABLE_NAME
GROUP BY page_id, ad_id
ORDER BY page_id, cnt DESC
LIMIT 1 BY page_id
Link to doc
There is one more solution with approximate calculations that can give an incompletely accurate result, but quickly (the number of hits can be counted through a subquery)
SELECT page_id, topK(1)(ad_id) ad_id
FROM table_name
GROUP BY page_id

Adding a count column in SQL Server for groups of records

I am trying to update an existing table with an individual count of the record on each row in a count column.
The table has the following columns that need to be incremented:
MBR_NO, CLAIM_N0, Effective_Dt, incr_count
So a sample might look like this before the run:
MBR_NO | CLAIM_N0 | Effective_Dt | incr_count |
-------+----------+----------------+------------+
1 | 2 | 1/1/2015 | NULL |
1 | 4 | 5/5/2015 | NULL |
1 | 5 | 6/7/2016 | NULL |
1 | 7 | 8/7/2016 | NULL |
2 | 2 | 4/3/2015 | NULL |
2 | 5 | 5/21/2015 | NULL |
3 | 8 | 3/27/2015 | NULL |
I want to count by MBR_NO and update the Incr_count to look like this:
MBR_NO | CLAIM_N0 | Effective_Dt | incr_count |
-------+----------+----------------+------------+
1 | 2 | 1/1/2015 | 1 |
1 | 4 | 5/5/2015 | 2 |
1 | 5 | 6/7/2016 | 3 |
1 | 7 | 8/7/2016 | 4 |
2 | 2 | 4/3/2015 | 1 |
2 | 5 | 5/21/2015 | 2 |
3 | 8 | 3/27/2015 | 1 |
I need to change that filed for processing later on.
I know this is not that complex but It seemed that the other topics offered solutions that don't incrementally update. Any help would be appreciated.
You could just do this in a query with
ROW_NUMBER() OVER (PARTITION BY MBR_NO ORDER BY Effective_DT).
but does it matter if the number changes? i.e. in your example if you had
MBR_NO EffectiveDate RowNumber
------------------------------------
2 1/1/2017 1
2 5/1/2017 2
but if you inserted a row with an effective date of say 3/1/2017 it would change the row number for the 5/1/2017 row i.e.
MBR_NO EffectiveDate RowNumber
------------------------------------
2 1/1/2017 1
2 3/1/2017 2
2 5/1/2017 3
You can query as below:
Select MBR_NO, CLAIM_N0, Effective_Dt,
incr_count = count(MBR_NO) over(Partition by MBR_NO order by Effective_Dt)
from yourtable
Output as below:
+--------+----------+--------------+------------+
| MBR_NO | CLAIM_N0 | Effective_Dt | incr_count |
+--------+----------+--------------+------------+
| 1 | 2 | 2015-01-01 | 1 |
| 1 | 4 | 2015-05-05 | 2 |
| 1 | 5 | 2016-06-07 | 3 |
| 1 | 7 | 2016-08-07 | 4 |
| 2 | 2 | 2015-04-03 | 1 |
| 2 | 5 | 2015-05-21 | 2 |
| 3 | 8 | 2015-03-27 | 1 |
+--------+----------+--------------+------------+

Update/multiply a field based on a value in another field

I am new to SQL and have the following issue I would like to solve. The table I would like to edit looks like this:
ID | ShopID | ProductID | PurchasePrice
1 | 1 | 111 | 1,00
2 | 2 | 111 | 1,40
3 | 3 | 111 | 1,30
4 | 1 | 222 | 2,00
5 | 2 | 222 | 2,50
6 | 3 | 222 | 2,90
7 | 1 | 333 | 3,00
8 | 2 | 333 | 3,80
9 | 3 | 333 | 3,90
ID (unique)
ShopID (3 different values, representing 3 different shops)
ProductID (refers to unique id of different table where more common product info is stored) the same value is available three times for every different ShopID
PurchasePrice (over time shops 2 and 3 have edited their pricing, it's a mess now)
The Value of PurchasePrice for ShopID 2 and 3 should be 10% higher than the PurchasePrice for ShopID 1 where ProductID is the same. How can I easily do this in SQL server 2008?
The table should look like this:
ID | ShopID | ProductID | PurchasePrice
1 | 1 | 111 | 1,00
2 | 2 | 111 | 1,10
3 | 3 | 111 | 1,10
4 | 1 | 222 | 2,00
5 | 2 | 222 | 2,20
6 | 3 | 222 | 2,20
7 | 1 | 333 | 3,00
8 | 2 | 333 | 3,30
9 | 3 | 333 | 3,30
UPDATE t
SET t.PurchasePrice = p.PurchasePrice*1,10
FROM Table t
LEFT JOIN (
SELECT ProductID,PurchasePrice FROM Table WHERE ShopID=1) p ON t.ProductID = p.ProductID
WHERE t.ShopID<>1
Here we get the list of prices in Shop 1 (See the left join query) and update prices of shops other than 1 to shop 1's ProductPrice * 1,10

Resources