SQL Server Join temp tables and Pivot - sql-server

I have two tables with data
TABLE 1:
Counts of service for weekdays
-------------------------------------------------------
| Day of Wk| Sun | Mon | Tue | Wed | Thu | Fri | Sat |
| 1 | 50 | 0 | 0 | 0 | 0 | 0 | 0 |
| 2 | 0 | 75 | 0 | 0 | 0 | 0 | 0 |
| 3 | 0 | 0 | 89 | 0 | 0 | 0 | 0 |
TABLE 2:
Table 2 with Production Totals by for selected services (Prod A - C) by weekday
-------------------------------------------------------
| Day of Wk| Date | Prod_A | Prod_B | Prod_C |
| 1 | 2015-01-01 | 4000 | 8000 | 9000 |
| 2 | 2015-01-14 | 3000 | 7000 | 8000 |
| 3 | 2015-01-05 | 2000 | 2000 | 5000 |
I need a query to produce this table:
Service counts of Weekdays = Total Service counts of table 1 in a column
-------------------------------------------------------
| Day of Wk | Service_Count | Prod_A | Prod_B | Prod_C |
| Sun | 50 | 4000 | 8000 | 9000 |
| Mon | 75 | 3000 | 7000 | 8000 |
| Tue | 89 | 2000 | 2000 | 5000 |
I am pretty new to pivoting and not sure if pivot is way to go for this or not.
In this recordset the Day of Wk column represents the day of the week, i.e. 1=Sunday

Not sure but looks simple to me.Sorry if I have not understood your question.
select t1.days_of_Week,(t1.sun+t1.mon+t1.tue+t1.wed+t1.thr+t1.fri+t1.sat)
Service_Count, t2.Prod_A,t2.Prod_B,t2.Prod_C
from Table1 t1,Table2 t2
where t1.days_of_week = t2.days_of_Week;

If you are trying to produce what you shared then the following query should do the job... #Swazzy
SELECT unpiv.[Day] AS Days_of_Week, unpiv.[Count] AS Service_Count,t2.Prod_A,t2.Prod_B,t2.Prod_C
FROM ( SELECT t.* FROM Table1 t) d
UNPIVOT
(
[Count]
for [Day] in (Sun, Mon, Tue, Wed, Thurs, Fri)
) unpiv
INNER JOIN Table2 t2 ON t2.Days_of_week = unpiv.days_of_week
WHERE unpiv.[Count] > 0

Related

UPDATE Column value with a count of rows with certain values

Have to update column value with a count of player's rows in table.
Table_Player :
ID | PlayerNr | session_type | Date | CountSes |
------------------------------------------------------------
1 | 1001 | cancelled | 2017-01-01 |
2 | 1001 | ready | 2017-06-06 |
3 | 1002 | ready | 2017-02-02 |
4 | 1002 | ready | 2017-04-04 |
5 | 1003 | waiting | 2017-03-03 |
6 | 1003 | ready | 2017-05-05 |
7 | 1004 | waiting | 2017-10-10 |
8 | 1004 | ready | 2017-11-11 |
9 | 1004 | waiting | 2017-12-12 |
10 | 0 | test | |
I've used :
UPDATE a
SET a.CountSes = b.cnt
FROM Table_Player a
JOIN
(SELECT PlayerNr, COUNT(*) cnt
FROM Table_Player
WHERE PlayerNr <> '0'
GROUP BY PlayerNr)
b ON a.PlayerNr = b.PlayerNr
This does the job but now I need a more detailed count.
Rules are:
session_type = 'waiting' . . Row will be counted only when it's the newest row of player.
PlayerNr = '0' . . . . . . . . . . . Dummy-player's rows will be ignored.
From sample above, the result should be:
ID | PlayerNr | session_type | Date | CountSes |
------------------------------------------------------------
1 | 1001 | cancelled | 2017-01-01 | 2
2 | 1001 | ready | 2017-06-06 | 2
3 | 1002 | ready | 2017-02-02 | 2
4 | 1002 | ready | 2017-04-04 | 2
5 | 1003 | waiting | 2017-03-03 | 1
6 | 1003 | ready | 2017-05-05 | 1
7 | 1004 | waiting | 2017-10-10 | 2
8 | 1004 | ready | 2017-11-11 | 2
9 | 1004 | waiting | 2017-12-12 | 2
10 | 0 | test | |
This goes beyond my knowledge, any Hints ?
Database is SQL Server 2014 SP2.
Thanks for your help.
I have used IIF and Partitioning function ROW_NUMBER to filter ignore waiting rows that are not new and also used SUM instead of COUNT
UPDATE t
SET CountSes = ISNULL(CNT, 0)
FROM Table_Player as t
LEFT JOIN (
SELECT SUM(IIF(session_type = 'waiting'
AND RN > 1, 0, 1)) AS CNT
, PlayerNr
FROM (
SELECT *
, ROW_NUMBER() OVER (
PARTITION BY PlayerNr ORDER BY DATE DESC
) RN
FROM Table_Player
WHERE (PlayerNr <> 0)
) t
GROUP BY PlayerNr
) as p ON p.PlayerNr = t.PlayerNr
rextester demo: http://rextester.com/NBHXYL39648

SQL Server query for next row value where previous row value

This query gives me Event values from 1 to 20 within an hour, how to add to that if a consecutive Event value is >=200 as well?
SELECT ID, count(Event) as numberoftimes
FROM table_name
WHERE Event >=1 and Event <=20
GROUP BY ID, DATEPART(HH, AtHour)
HAVING DATEPART(HH, AtHour) <= 1
ORDER BY ID desc
In this dummy 24h table:
+----+-------+--------+
| ID | Event | AtHour |
+----+-------+--------+
| 1 | 1 | 11:00 |
| 1 | 4 | 11:01 |
| 1 | 1 | 11:02 |
| 1 | 20 | 11:03 |
| 1 | 200 | 11:04 |
| 1 | 1 | 13:00 |
| 1 | 1 | 13:05 |
| 1 | 2 | 13:06 |
| 1 | 500 | 13:07 |
| 1 | 39 | 13:10 |
| 1 | 50 | 13:11 |
| 1 | 2 | 13:12 |
+----+-------+--------+
I would like to select IDs with Event with values with range between 1 and 20 followed immediately by value greater than or equal to 200 within an hour.
Expected result should be something like that:
+----+--------+
| ID | AtHour |
+----+--------+
| 1 | 11 |
| 1 | 13 |
| 2 | 11 |
| 2 | 14 |
| 3 | 09 |
| 3 | 12 |
+----+--------+
or just how many times it has happened for unique ID instead of which hour.
Please excuse me I am still rusty with post formatting!
CREATE TABLE data (Id INT, Event INT, AtHour SMALLDATETIME);
INSERT data (Id, Event, AtHour) VALUES
(1,1,'2017-03-16 11:00:00'),
(1,4,'2017-03-16 11:01:00'),
(1,1,'2017-03-16 11:02:00'),
(1,20,'2017-03-16 11:03:00'),
(1,200,'2017-03-16 11:04:00'),
(1,1,'2017-03-16 13:00:00'),
(1,1,'2017-03-16 13:05:00'),
(1,2,'2017-03-16 13:06:00'),
(1,500,'2017-03-16 13:07:00'),
(1,39,'2017-03-16 13:10:00')
;
; WITH temp as (
SELECT rownum = ROW_NUMBER() OVER (PARTITION BY id ORDER BY AtHour)
, *
FROM data
)
SELECT a.id, DATEPART(HOUR, a.AtHour) as AtHour, COUNT(*) AS NumOfPairs
FROM temp a JOIN temp b ON a.rownum = b.rownum-1
WHERE a.Event BETWEEN 1 and 20 AND b.Event >= 200
AND DATEDIFF(MINUTE, a.AtHour, b.AtHour) <= 60
GROUP BY a.id, DATEPART(HOUR, a.AtHour)
;

SQL tables with different detail level - one containing the sum of the other

I am trying to build a simple model with tables containing forecast data.
The first I will call [Year Forecast] and the second [Month Forecast]. Like so:
| Year | Forecast |
-------------------
| 2018 | 144000 |
| 2019 | 180000 |
| 2020 | 220000 |
| .... | ...... |
I want the DB to allow manual input in the [Year Forecast] for [Year] > year(getdate())+2. So in the example the forecast number of 2020 would have been manually entered as a whole number. (Note that Year would be a unique identifier)
For [Year] < year(getdate())+2 the table [Year Forecast] should take the sum of [Month Forecast]. This would be for 2018 and 2019 in this example.
| ID | Year | Month | Forecast |
--------------------------------
| 1 | 2018 | 1 | 12000 |
| 2 | 2018 | 2 | 12000 |
| 3 | 2018 | 3 | 12000 |
| 4 | 2018 | 4 | 12000 |
| 5 | 2018 | 5 | 12000 |
| 6 | 2018 | 6 | 12000 |
| 7 | 2018 | 7 | 12000 |
| 8 | 2018 | 8 | 12000 |
| 9 | 2018 | 9 | 12000 |
| 10 | 2018 | 10 | 12000 |
| 11 | 2018 | 11 | 12000 |
| 12 | 2018 | 12 | 12000 |
| 13 | 2019 | 1 | 15000 |
| 14 | 2019 | 2 | 15000 |
| .. | .... | ..... | ........ |
Relationship would be straightforward, but I want to define a procedure that takes the sum of Forecast of the related year in [Month Forecast] and prohibits manual data input for [Year] < year(getdate())+2
I've come quite far in my SQL journey and I know this should be possible but is still a bit above my skill level. How should I go about this?

SQL percentage of total items by group

I have the following pseudo-table which shows product orders:
+---------+------+--------------+---------------+
| OrderID | Year | PriorityCode | ShippedOnTime |
+---------+------+--------------+---------------+
| 1 | 2014 | A | Y |
| 2 | 2014 | B | Y |
| 3 | 2014 | A | N |
| 4 | 2015 | C | Y |
| 5 | 2015 | B | Y |
| 6 | 2015 | A | N |
| 7 | 2015 | A | N |
| 8 | 2015 | B | N |
| 9 | 2015 | C | Y |
| 10 | 2015 | C | Y |
+---------+------+--------------+---------------+
I need to find a way to query to find percentages of ShippedOntime grouped by PriorityCode, not as a total number of rows. For Example:
PriorityCode: A - Total 4, 1 was shipped on time = 25%
PriorityCode: B - Total 3, 2 were shipped on time = 33.3%
PriorityCode: C - Total 3, 3 were shipped on time = 100%
+--------------+------------+
| PriorityCode | Percentage |
+--------------+------------+
| A | 25 |
| B | 33.3 |
| C | 100 |
+--------------+------------+
Been looking into using the Over() function and then Grouping the results, but cant seem to figure it out.
Id like to also be able to group it by year also, but small steps!
You can use conditional statements inside a group by function, such as count or sum to achieve the desired output:
select PriorityCode, sum(case when ShippedOnTime="Y" then 1 else 0 end)/count(*) * 100 as percentage
from table
group by PriorityCode
This should do the trick:
SELECT
Year,
PriorityCode,
CAST(SUM(CASE WHEN ShippedOnTime = 'Y'
THEN 100.0 ELSE 0
END)
/ COUNT(*) as DECIMAL(4,1)) Percentage
FROM yourtable
GROUP BY
PriorityCode, Year

range sql query result range

ID | NAME | AGE | ADDRESS | SALARY |
+----+----------+-----+-----------+----------+
| 1 | Ramesh | 32 | Ahmedabad | 2000.00 |
| 2 | Khilan | 25 | Delhi | 1500.00 |
| 3 | kaushik | 23 | Kota | 2000.00 |
| 4 | Chaitali | 25 | Mumbai | 6500.00 |
| 5 | Hardik | 27 | Bhopal | 8500.00 |
| 6 | Komal | 22 | MP | 4500.00 |
| 7 | Muffy | 24 | Indore | 10000.00
I want to show result below using ms sql server
SALARY
-------------------
0 - 1500 (1)
1500 - 3000(2)
3000 - 4500(1)
4500-6000(0)
6000-7500(0)
7500 - 9000(1)
9000-10500(1)
This is something of a pain, because you want the 0 counts. Here is one method:
with ranges as (
select 0 as low, 1500 as high union all
select 1500, 3000 union all
select 3000, 4500 union all
. . .
)
select r.low, r.high, count(t.salary)
from ranges r left join
t
on t.salary >= r.low and
t.salary < r.high
group by r.low, r.high
order by r.low;
If you really want, you can use string manipulations to put the range as a single character column. In general, I prefer to have them as two separate columns.

Resources