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
Related
I have the following table T1 (sample shown), which shows the category for each client (each with a unique ID) on a specific date and his category on the next date:
+------------+----------------+----------+---------------+
| DATE | ID | STAGE | STAGE_NEXT |
+------------+----------------+----------+---------------+
| 2014-07-01 | 10010101841033 | 1 | 1 |
| 2015-07-01 | 74610108542146 | 1 | 1 |
| 2014-10-01 | 47970108841775 | 3 | 3 |
| 2014-10-01 | 48870108841816 | 2 | 3 |
| 2014-10-01 | 32910097439541 | 1 | 1 |
| 2016-04-01 | 46930097440855 | 2 | 3 |
| 2016-04-01 | 47380097440931 | 2 | 3 |
| 2016-04-01 | 54560097441411 | 3 | 3 |
+------------+----------------+----------+---------------+
Table info:
- Rows: 513,000
- Date range: 2013-01-01 to 2019-10-01
- Stages: 1 - 3
I need to create a new column in T1, which will flag the date a client moved to Stage 1 if at any point he was in Stage 3. For example if we take 1 client from T1 by using this code:
SELECT [DATE], ID, STAGE, STAGE_NEXT
FROM T1
WHERE ID = '74610108542146'
ORDER BY [DATE]
We get the following result:
+------------+----------------+-------+------------+
| DATE | ID | STAGE | STAGE_NEXT |
+------------+----------------+-------+------------+
| 2015-07-01 | 74610108542146 | 1 | 1 |
| 2015-10-01 | 74610108542146 | 1 | 1 |
| 2016-01-01 | 74610108542146 | 1 | 2 |
| 2016-04-01 | 74610108542146 | 2 | 1 |
| 2016-07-01 | 74610108542146 | 1 | 1 |
| 2016-10-01 | 74610108542146 | 1 | 2 |
| 2017-01-01 | 74610108542146 | 2 | 3 |
| 2017-04-01 | 74610108542146 | 3 | 3 |
| 2017-07-01 | 74610108542146 | 3 | 2 |
| 2017-10-01 | 74610108542146 | 2 | 1 |
| 2018-01-01 | 74610108542146 | 1 | 1 |
| 2018-04-01 | 74610108542146 | 1 | NULL |
+------------+----------------+-------+------------+
After the new column with the flag is added to T1 we should be able to get the following result using this code on T1:
SELECT [DATE], ID, STAGE, STAGE_NEXT, FLAG
FROM T1
WHERE ID = '74610108542146'
ORDER BY [DATE]
+------------+----------------+-------+------------+------+
| DATE | ID | STAGE | STAGE_NEXT | FLAG |
+------------+----------------+-------+------------+------+
| 2015-07-01 | 74610108542146 | 1 | 1 | 0 |
| 2015-10-01 | 74610108542146 | 1 | 1 | 0 |
| 2016-01-01 | 74610108542146 | 1 | 2 | 0 |
| 2016-04-01 | 74610108542146 | 2 | 1 | 0 |
| 2016-07-01 | 74610108542146 | 1 | 1 | 0 |
| 2016-10-01 | 74610108542146 | 1 | 2 | 0 |
| 2017-01-01 | 74610108542146 | 2 | 3 | 0 |
| 2017-04-01 | 74610108542146 | 3 | 3 | 0 |
| 2017-07-01 | 74610108542146 | 3 | 2 | 0 |
| 2017-10-01 | 74610108542146 | 2 | 1 | 1 |
| 2018-01-01 | 74610108542146 | 1 | 1 | 0 |
| 2018-04-01 | 74610108542146 | 1 | NULL | 0 |
+------------+----------------+-------+------------+------+
If the client never moved to Stage 3 then the flag for the client is always 0
You could calculate and update the new FLAG column from a CTE.
The update statement uses the LAG function to use the previous STAGE in the calculation of FLAG.
;WITH CTE AS
(
SELECT ID, [DATE], FLAG,
CASE
WHEN STAGE = 2
AND STAGE_NEXT = 1
AND LAG(STAGE) OVER (PARTITION BY ID ORDER BY IIF(STAGE=2 AND STAGE_NEXT=2,0,1), [DATE]) = 3
THEN 1
ELSE 0
END AS CalcFlag
FROM T1
WHERE ID = '10010101841033' -- optional, to target only 1 ID
)
UPDATE CTE
SET FLAG = CalcFlag
WHERE (FLAG IS NULL OR FLAG != CalcFlag);
The IIF(STAGE=2 AND STAGE_NEXT=2,0,1) in the LAG is used to make the calculation also work when the stage 2 is repeated.
Test it on rextester here
Try this,
DECLARE #T1 table
(
[DATE] date,ID numeric(18,0),STAGE int,STAGE_NEXT int
)
INSERT INTO #T1 VALUES
('2013-01-01',10010101841033,1,1 ),
('2013-04-01',10010101841033,1,3 ),
('2013-07-01',10010101841033,3,3 ),
('2013-10-01',10010101841033,3,2 ),
('2014-01-01',10010101841033,2,1 ),
('2014-04-01',10010101841033,1,1 ),
('2014-07-01',10010101841033,1,1 ),
('2014-10-01',10010101841033,1,NULL),
('2014-07-01',47820108841771,1,2)
SELECT A.DATE,A.ID,A.STAGE,A.STAGE_NEXT,
CASE WHEN B.ID IS NOT NULL AND (STAGE_NEXT=1 AND STAGE>STAGE_NEXT) THEN 1 ELSE 0 END AS FLAG
FROM #T1 A
LEFT JOIN
(
SELECT DISTINCT ID AS ID
FROM #T1
WHERE STAGE_NEXT=3
)B
ON A.ID=B.ID
Let's say I have the following table (data is completely fiction):
ID | MonthDate | PersonID | Name | Status | MonthsAgoSinceLastCheck
1 | 2017-12 | 900 | Jack | Ill | -
2 | 2018-01 | 900 | Jack | Ill | 1
3 | 2018-02 | 900 | Jack | Ill | 2
4 | 2018-03 | 900 | Jack | Healthy | 1
5 | 2017-02 | 901 | Bill | Ill | -
6 | 2017-03 | 901 | Bill | Ill | 1
7 | 2017-05 | 901 | Bill | Healthy | 1
For each record, I would like to see the previous status that person had X months ago since last check (column MonthsAgoSinceLastCheck). Notice that MonthDate can skip months.
So in this case, the result would be
ID | MonthDate | PersonID | Name | Status | MonthsAgoSinceLastCheck | PreviousSatus
1 | 2017-12 | 900 | Jack | Ill | - | -
2 | 2018-01 | 900 | Jack | Ill | 1 | Ill
3 | 2018-02 | 900 | Jack | Ill | 2 | Ill
4 | 2018-03 | 900 | Jack | Healthy | 1 | Ill
5 | 2017-02 | 901 | Bill | Healthy | - | -
6 | 2017-03 | 901 | Bill | Healthy | 1 | Healthy
7 | 2017-05 | 901 | Bill | Ill | 2 | Healthy
Any sugestions/tips? I tried to do this with CTE's and self-joins but failed on both.
It's way easier to use full dates than year and months separately. The first thing you should do is generate a full date from your year + month. Then just self join with previous month, depending on the last check.
;WITH DataWithDates AS
(
SELECT
T.ID,
MonthDate = CONVERT(DATE, T.MonthDate + '-01'),
T.PersonID,
T.Name,
T.Status,
T.MonthsAgoSinceLastCheck
FROM
YourTable AS T
)
SELECT
D.ID,
D.MonthDate,
D.PersonID,
D.Name,
D.Status,
D.MonthsAgoSinceLastCheck,
PreviousStatus = N.Status
FROM
DataWithDates AS D
LEFT JOIN DataWithDates AS N ON
D.PersonID = N.PersonID AND
N.MonthDate = DATEADD(MONTH, -1 * D.MonthsAgoSinceLastCheck, D.MonthDate)
I'm assuming your MonthDate has values for all rows, otherwise the conversion will fail. I'm also assuming that your - values for MonthsAgoSinceLastCheck are actually NULL.
try this:
select *,LAG(Status) OVER(Partition by Name Order by MonthDate,Id) AS PreviousSatus
from tab1
order by id
SQl Fiddle:http://sqlfiddle.com/#!18/04407/4
I have three SQL tables: Release (which represents a release of a movie), Media (which represents the individual pieces of recordable media in those releases; i.e. for Blu-ray/DVD combos, there will be two rows in Media, one Blu-ray and one DVD, that point back to the same row in Release) and MediaType (which defines Blu-ray, DVD, VHS, etc.). There's a one-to-many relationship for Release/Media and MediaType/Media, with Media being on the "many" side of both relationships. I have a view for Release, vRelease, which contains aggregate functions, such as a COUNT that shows how many media are associated with that release. This is what I have for this view so far:
SELECT dbo.Release.ReleaseID
,dbo.Release.Name
,CASE WHEN Release.Compilation = 0 THEN 'No' WHEN Release.Compilation = 1 THEN 'Yes' END AS Compilation
,dbo.Release.Owner
,CASE WHEN Release.LentOut = 0 THEN 'No' WHEN Release.LentOut = 1 THEN 'Yes' END AS LentOut
,COUNT(dbo.Media.ReleaseID) AS NumberOfMedia
,MIN(dbo.Media.MediaID) AS FirstMediaID
,MIN(dbo.MediaType.Name) AS FirstMediaType
FROM dbo.MediaType INNER JOIN
dbo.Media ON dbo.MediaType.MediaTypeID = dbo.Media.MediaTypeID RIGHT OUTER JOIN
dbo.Release ON dbo.Media.ReleaseID = dbo.Release.ReleaseID
GROUP BY dbo.Release.ReleaseID, dbo.Release.Name, dbo.Release.Compilation, dbo.Release.Owner, dbo.Release.LentOut
You'll notice that I've also included two other aggregate columns: FirstMediaID grabs the ID of the media associated with that release that appears first in the Media table (i.e. if a release has two DVDs associated with it, it gets one with the lower ID value). This column on its own isn't useful; what I want to do is then, in turn, get the MediaType that that Media is associated with. In other words, I want a column that shows the MediaType of the first Media that is attached to each Release. The column after that, FirstMediaType, is supposed to do that, but it instead gets the MediaType among all of the Media associated with the Release and picks the one that is alphabetically first - which means that Blu-ray will always be prioritized over DVD (which is fine), but Audio CD will always be prioritized over everything else (which is not fine).
How do I get the FirstMediaType column in this view to get the MediaType of the Media identified in FirstMediaID?
UPDATE: Here are the tables, their columns and some sample rows.
A couple from Release:
+-----------+----------------------------------------+-------+-------------+---------+
| ReleaseID | Name | Owner | Compilation | LentOut |
+-----------+----------------------------------------+-------+-------------+---------+
| 2 | Alice in Wonderland | NULL | 0 | 0 |
| 6 | 4 Film Favorites - Family Comedies | NULL | 1 | 0 |
| 8 | Aladdin | NULL | 0 | 0 |
| 463 | Harry Potter and the Half-Blood Prince | NULL | 0 | 1 |
| 534 | Spirited Away | Ryan | 0 | 0 |
| 571 | The Original Christmas Classics | NULL | 1 | 0 |
+-----------+----------------------------------------+-------+-------------+---------+
Compilation indicates a release that has more than one movie in it.
Corresponding entries in Media:
+---------+-------------+-------------------------------------------------------------------------------------+-----------+
| MediaID | MediaTypeID | Name | ReleaseID |
+---------+-------------+-------------------------------------------------------------------------------------+-----------+
| 2 | 2 | Movie | 2 |
| 3 | 1 | Movie | 2 |
| 12 | 1 | Space Jam; Looney Tunes: Back in Action | 6 |
| 13 | 1 | Funky Monkey; Osmosis Jones | 6 |
| 17 | 3 | Movie | 8 |
| 620 | 1 | Movie | 463 |
| 726 | 1 | Movie | 534 |
| 807 | 1 | Rudolph the Red-Nosed Reindeer; Cricket on the Hearth | 571 |
| 808 | 1 | Frosty the Snowman; Frosty Returns | 571 |
| 809 | 1 | Santa Claus is Comin' to Town!; Mr. Magoo's Christmas Carol; The Little Drummer Boy | 571 |
| 810 | 4 | Tracks 1-7 | 571 |
+---------+-------------+-------------------------------------------------------------------------------------+-----------+
First few in MediaType:
+-------------+--------------+
| MediaTypeID | Name |
+-------------+--------------+
| 1 | DVD Disc |
| 2 | Blu-ray Disc |
| 3 | VHS |
| 4 | Audio CD |
+-------------+--------------+
The corresponding entries in vRelease SHOULD be this:
+-----------+----------------------------------------+-------------+-------+---------+---------------+--------------+----------------+
| ReleaseID | Name | Compilation | Owner | LentOut | NumberOfMedia | FirstMediaID | FirstMediaType |
+-----------+----------------------------------------+-------------+-------+---------+---------------+--------------+----------------+
| 2 | Alice in Wonderland | No | NULL | No | 2 | 2 | Blu-ray Disc |
| 6 | 4 Film Favorites - Family Comedies | Yes | NULL | No | 2 | 12 | DVD Disc |
| 8 | Aladdin | No | NULL | No | 1 | 17 | VHS |
| 463 | Harry Potter and the Half-Blood Prince | No | NULL | Yes | 1 | 620 | DVD Disc |
| 534 | Spirited Away | No | Ryan | No | 1 | 726 | DVD Disc |
| 571 | The Original Christmas Classics | Yes | NULL | No | 4 | 807 | DVD Disc |
+-----------+----------------------------------------+-------------+-------+---------+---------------+--------------+----------------+
But it's actually this:
+-----------+----------------------------------------+-------------+-------+---------+---------------+--------------+----------------+
| ReleaseID | Name | Compilation | Owner | LentOut | NumberOfMedia | FirstMediaID | FirstMediaType |
+-----------+----------------------------------------+-------------+-------+---------+---------------+--------------+----------------+
| 2 | Alice in Wonderland | No | NULL | No | 2 | 2 | Blu-ray Disc |
| 6 | 4 Film Favorites - Family Comedies | Yes | NULL | No | 2 | 12 | DVD Disc |
| 8 | Aladdin | No | NULL | No | 1 | 17 | VHS |
| 463 | Harry Potter and the Half-Blood Prince | No | NULL | Yes | 1 | 620 | DVD Disc |
| 534 | Spirited Away | No | Ryan | No | 1 | 726 | DVD Disc |
| 571 | The Original Christmas Classics | Yes | NULL | No | 4 | 807 | Audio CD |
+-----------+----------------------------------------+-------------+-------+---------+---------------+--------------+----------------+
It's that last one that's the problem.
I ended up finding a simple way to do what I wanted. It isn't as fancy as Used_By_Already's answer (which did end up working, as far as I could tell) and probably breaks a SQL Best Practices rule somewhere, but it's much easier to understand and maintain - at least for my newbie brain.
Since the problem was trying to get the view to use an aggregate column it calculated in a join, I just split the two-step action over two views. vReleasePre has all of the columns I outlined in my original query except for FirstMediaType. vRelease now simply takes all of the columns from vReleasePre and adds FirstMediaType, which takes its value from a join at the end: LEFT OUTER JOIN dbo.vMedia ON dbo.vReleasePre.FirstMediaID = dbo.vMedia.MediaID, where vMedia is a view with all the columns from Media, plus the MediaType column (I already had vMedia lying around).
Since this database is being used in an ASP.NET MVC web application via Entity Framework, and EF has been pretty strange about what it will and won't accept into the data model, I figure that a simple, if roundabout, solution is probably going to be my best option.
vReleasePre:
SELECT dbo.Release.ReleaseID
,dbo.Release.Name
,CASE WHEN Release.Compilation = 0 THEN 'No' WHEN Release.Compilation = 1 THEN 'Yes' END AS Compilation
,dbo.Release.Owner
,CASE WHEN Release.LentOut = 0 THEN 'No' WHEN Release.LentOut = 1 THEN 'Yes' END AS LentOut
,COUNT(dbo.Media.ReleaseID) AS NumberOfMedia
,MIN(dbo.Media.MediaID) AS FirstMediaID
FROM dbo.MediaType INNER JOIN
dbo.Media ON dbo.MediaType.MediaTypeID = dbo.Media.MediaTypeID RIGHT OUTER JOIN
dbo.Release ON dbo.Media.ReleaseID = dbo.Release.ReleaseID
GROUP BY dbo.Release.ReleaseID, dbo.Release.Name, dbo.Release.Compilation, dbo.Release.Owner, dbo.Release.LentOut
vRelease:
SELECT dbo.vReleasePre.ReleaseID
,dbo.vReleasePre.Name
,dbo.vReleasePre.Compilation
,dbo.vReleasePre.Owner
,dbo.vReleasePre.LentOut
,dbo.vReleasePre.NumberOfMedia
,dbo.vMedia.MediaType
FROM dbo.vReleasePre LEFT OUTER JOIN
dbo.vMedia ON dbo.vReleasePre.FirstMediaID = dbo.vMedia.MediaID
A very convenient technique that returns whole rows associated with needs such as "First", "Last", "Earliest", "Latest" is to use row_number() over(). Here you want the "first media type", so it is relevant here.
As you will see in the following query joining the [Media] table is replaced with a subquery that includes a row number calculation. Here we partition by ReleaseID and order by MediaID, so, for each ReleaseID the first row will be the one with the lowest MediaID value. Then in the join to this derived table an extra condition is added to only consider rows with a row number of 1.
Proposed Query
SELECT
r.ReleaseID
, m.MediaID
, mt.MediaTypeID
, mt.name MediaName
, r.Name
, CASE
WHEN r.Compilation = 0 THEN 'No'
WHEN r.Compilation = 1 THEN 'Yes'
END AS compilation
, r.Owner
, CASE
WHEN r.LentOut = 0 THEN 'No'
WHEN r.LentOut = 1 THEN 'Yes'
END AS lentout
FROM dbo.Release r
INNER JOIN (
SELECT
Media.*
, ROW_NUMBER() OVER(PARTITION BY ReleaseID
ORDER BY MediaID) AS rn
FROM dbo.Media
) m ON r.ReleaseID = m.ReleaseID and rn = 1
INNER JOIN dbo.MediaType mt ON m.MediaTypeID = mt.MediaTypeID
Result
| ReleaseID | MediaID | MediaTypeID | MediaName | Name | compilation | Owner | lentout |
|-----------|---------|-------------|--------------|----------------------------------------|-------------|--------|---------|
| 2 | 2 | 2 | Blu-ray Disc | Alice in Wonderland | No | (null) | No |
| 6 | 12 | 1 | DVD Disc | 4 Film Favorites - Family Comedies | Yes | (null) | No |
| 8 | 17 | 3 | VHS | Aladdin | No | (null) | No |
| 463 | 620 | 1 | DVD Disc | Harry Potter and the Half-Blood Prince | No | (null) | Yes |
| 534 | 726 | 1 | DVD Disc | Spirited Away | No | Ryan | No |
| 571 | 807 | 1 | DVD Disc | The Original Christmas Classics | Yes | (null) | No |
Demo available at SQLFiddle
The easiest way would be to add another join to your MediaType table on FirstMediaId = MediaType.MediaId
;WITH data AS (
SELECT dbo.Release.ReleaseID
,dbo.Release.Name
,CASE WHEN Release.Compilation = 0 THEN 'No' WHEN Release.Compilation = 1 THEN 'Yes' END AS Compilation
,dbo.Release.Owner
,CASE WHEN Release.LentOut = 0 THEN 'No' WHEN Release.LentOut = 1 THEN 'Yes' END AS LentOut
,COUNT(dbo.Media.ReleaseID) AS NumberOfMedia
,MIN(dbo.Media.MediaID) AS FirstMediaID
FROM dbo.MediaType
INNER JOIN dbo.Media
ON dbo.MediaType.MediaTypeID = dbo.Media.MediaTypeID
RIGHT OUTER JOIN dbo.Release
ON dbo.Media.ReleaseID = dbo.Release.ReleaseID
GROUP BY dbo.Release.ReleaseID, dbo.Release.Name, dbo.Release.Compilation, dbo.Release.Owner, dbo.Release.LentOut
)
SELECT data.ReleaseId
,data.Name
,data.Compilation
,data.Owner
,data.LentOut
,data.NumberOfMedia
,data.FirstMediaId
,MediaType.Name as FirstMediaName
FROM data
LEFT OUTER JOIN dbo.MediaType
ON data.FirstMediaId = MediaType.MediaTypeId
for the newbie brain, this is the subquery I used
SELECT
ROW_NUMBER() OVER(PARTITION BY ReleaseID
ORDER BY MediaID) AS rn
, Media.*
FROM dbo.Media
and this is what it does (see the rn column)
| rn | MediaID | MediaTypeID | Name | ReleaseID |
|----|---------|-------------|-------------------------------------------------------------------------------------|-----------|
| 1 | 2 | 2 | Movie | 2 |
| 2 | 3 | 1 | Movie | 2 |
| 1 | 12 | 1 | Space Jam; Looney Tunes: Back in Action | 6 |
| 2 | 13 | 1 | Funky Monkey; Osmosis Jones | 6 |
| 1 | 17 | 3 | Movie | 8 |
| 1 | 620 | 1 | Movie | 463 |
| 1 | 726 | 1 | Movie | 534 |
| 1 | 807 | 1 | Rudolph the Red-Nosed Reindeer; Cricket on the Hearth | 571 |
| 2 | 808 | 1 | Frosty the Snowman; Frosty Returns | 571 |
| 3 | 809 | 1 | Santa Claus is Comin' to Town!; Mr. Magoo's Christmas Carol; The Little Drummer Boy | 571 |
| 4 | 810 | 4 | Tracks 1-7 | 571 |
Now keep only those rows with 1 in the rn column:
| rn | MediaID | MediaTypeID | Name | ReleaseID |
|----|---------|-------------|-------------------------------------------------------|-----------|
| 1 | 2 | 2 | Movie | 2 |
| 1 | 12 | 1 | Space Jam; Looney Tunes: Back in Action | 6 |
| 1 | 17 | 3 | Movie | 8 |
| 1 | 620 | 1 | Movie | 463 |
| 1 | 726 | 1 | Movie | 534 |
| 1 | 807 | 1 | Rudolph the Red-Nosed Reindeer; Cricket on the Hearth | 571 |
Then join just those rows to Releases and MediaType
Bingo
= the wanted result.
Not hard, really not hard. You really will want to learn about those window functions because they can solve heaps of problems.
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)
;
I have a table that holds values for particular months:
| MFG | DATE | FACTOR |
-----------------------------
| 1 | 2013-01-01 | 1 |
| 2 | 2013-01-01 | 0.8 |
| 2 | 2013-02-01 | 1 |
| 2 | 2013-12-01 | 1.55 |
| 3 | 2013-01-01 | 1 |
| 3 | 2013-04-01 | 1.3 |
| 3 | 2013-05-01 | 1.2 |
| 3 | 2013-06-01 | 1.1 |
| 3 | 2013-07-01 | 1 |
| 4 | 2013-01-01 | 0.9 |
| 4 | 2013-02-01 | 1 |
| 4 | 2013-12-01 | 1.8 |
| 5 | 2013-01-01 | 1.4 |
| 5 | 2013-02-01 | 1 |
| 5 | 2013-10-01 | 1.3 |
| 5 | 2013-11-01 | 1.2 |
| 5 | 2013-12-01 | 1.5 |
What I would like to do is pivot these using a calendar table (already defined):
And finally, cascade the NULL columns to use the previous value.
What I've got so far is a query that will populate the NULLs with the last value for mfg = 3. Each mfg will always have a value for the first of the year. My question is; how do I pivot this and extend to all mfg?
SELECT c.[date],
f.[factor],
Isnull(f.[factor], (SELECT TOP 1 factor
FROM factors
WHERE [date] < c.[date]
AND [factor] IS NOT NULL
AND mfg = 3
ORDER BY [date] DESC)) AS xFactor
FROM (SELECT [date]
FROM calendar
WHERE Datepart(yy, [date]) = 2013
AND Datepart(d, [date]) = 1) c
LEFT JOIN (SELECT [date],
[factor]
FROM factors
WHERE mfg = 3) f
ON f.[date] = c.[date]
Result
| DATE | FACTOR | XFACTOR |
---------------------------------
| 2013-01-01 | 1 | 1 |
| 2013-02-01 | (null) | 1 |
| 2013-03-01 | (null) | 1 |
| 2013-04-01 | 1.3 | 1.3 |
| 2013-05-01 | 1.2 | 1.2 |
| 2013-06-01 | 1.1 | 1.1 |
| 2013-07-01 | 1 | 1 |
| 2013-08-01 | (null) | 1 |
| 2013-09-01 | (null) | 1 |
| 2013-10-01 | (null) | 1 |
| 2013-11-01 | (null) | 1 |
| 2013-12-01 | (null) | 1 |
SQL Fiddle
Don't know if you need the dates to be dynamic from the calender table or if mfg can be more than 5 but this should give you some ideas.
select *
from (
select c.date,
t.mfg,
(
select top 1 f.factor
from factors as f
where f.date <= c.date and
f.mfg = t.mfg and
f.factor is not null
order by f.date desc
) as factor
from calendar as c
cross apply(values(1),(2),(3),(4),(5)) as t(mfg)
) as t
pivot (
max(t.factor) for t.date in ([20130101], [20130201], [20130301],
[20130401], [20130501], [20130601],
[20130701], [20130801], [20130901],
[20131001], [20131101], [20131201])
) as P
SQL Fiddle