sql server how to find the max of a count row - sql-server-2008

I have written the following query:
DECLARE #countryCode TINYINT
SET #countryCode = 1;
SELECT
DivingSite.SiteCode,
DATEPART(Month, divingDate) AS 'month number' ,
COUNT (divingNo) AS 'number of dives in month'
FROM
DivingSite
INNER JOIN
tblDiving ON DivingSite.SiteCode = tblDiving.SiteCode
WHERE
DivingSite.countryCode = #countryCode
AND divingDate > DATEADD(year, -1, GETDATE())
GROUP BY
DivingSite.SiteCode, DATEPART(Month, divingDate)
The result of this query is:
siteCode | month number | number of dives in month
--------------------------------------------------
107 1 1
108 7 2
107 8 2
The thing is - for every siteCode I want to display only the month with the biggest number of dives. So I would like to have the result:
siteCode | month number | number of dives in month
--------------------------------------------------
108 7 2
107 8 2
How do I do that?

Try this - use a CTE (Common Table Expression) with a ROW_NUMBER function that "partitions" your data by the siteCode and numbers each row for a single siteCode starting at one - with the one with the highest number of dives having RowNum = 1 and any others having higher row numbers.
By selecting only those rows with RowNum = 1 you get only those entries for each siteCode with the highest number of dives.
DECLARE #countryCode TINYINT
SET #countryCode = 1;
;WITH RawData AS
(
SELECT
ds.SiteCode,
MonthNumber = DATEPART(Month, divingDate),
NumberOfDives = COUNT (divingNo),
RowNum = ROW_NUMBER() OVER (PARTITION BY ds.SiteCode ORDER BY COUNT(divingNo) DESC)
FROM
dbo.DivingSite ds
INNER JOIN
dbo.tblDiving d ON ds.SiteCode = d.SiteCode
WHERE
ds.countryCode = #countryCode
AND divingDate > DATEADD(year, -1, GETDATE())
GROUP BY
ds.SiteCode, DATEPART(Month, divingDate)
)
SELECT
SiteCode,
MonthNumber,
NumberOfDives
FROM
RawData
WHERE
RowNum = 1

You could create a query on top of the one you already have, like so:
select
DivingSite.SiteCode,
DATEPART(Month, divingDate) as 'month number' ,
count (divingNo) as 'number of dives in month'
into #dives
from DivingSite
inner join tblDiving on DivingSite.SiteCode = tblDiving.SiteCode
where
DivingSite.countryCode = #countryCode
and divingDate > DATEADD(year,-1,GETDATE())
group by
DivingSite.SiteCode,
DATEPART(Month, divingDate)
select d.* from #dives d join
(
SELECT
SiteCode,
MAX([number of dives in month]) MaxDives
FROM #dives
GROUP BY SiteCode
) max_dives on max_dives.SiteCode = d.SiteCode
and d.[number of dives in month] = max_dives.MaxDives

Related

Get recent count from a column

I would like to get the count of a column based on its recent status.
Please see table structure below:
id | visible | date
1 | 1 | 2021-07-22
2 | 1 | 2021-07-23
3 | 0 | 2021-07-24
4 | 1 | 2021-07-25
5 | 0 | 2021-07-26
6 | 0 | 2021-07-27
For example, if I query
SELECT COUNT(visible) AS latest_not_visible WHERE date = '2021-07-26'
then it should return
latest_not_visible
1
Since it only counts that date as not visible, it disregarded the count on 07/24 since 07/25 is visible
But if I query
SELECT COUNT(visible) AS latest_not_visible WHERE date = '2021-07-27'
latest_not_visible
2
since 07/26 and 07/27 are both non-visible and no date in between is visible
I already had the solution to the problem, but I would need help in optimizing this function:
IIF(datediff
(day,
(SELECT MAX(date) FROM t1 WHERE (visible = 0 OR visible = '-1' OR visible = '-3') AND item_id = vp.item_id AND [date] <= vp.date),
(SELECT MAX(date) FROM t1 WHERE visible = 1 AND item_id = vp.item_id AND [date] <= vp.date)) IS NULL
OR datediff(day,
(SELECT MAX(date) FROM t1 WHERE (visible = 0 OR visible = '-1' OR visible = '-3') AND item_id = vp.item_id AND [date] <= vp.date),
(SELECT MAX(date) FROM t1 WHERE visible = 1 AND item_id = vp.item_id AND [date] <= vp.date)) < 0,
(SELECT COUNT(1) FROM t1 WHERE (visible = 0 OR visible = '-1' OR visible = '-3') AND item_id = vp.item_id AND [date] <= vp.date), 0)
AS times_not_visible,
table vp is the original table same with t1
Rather than counting them, you're better to calculate the number of days between the last visible and not visible on or before that date. So something like this...
SELECT DATEDIFF(
SELECT MAX(date) FROM YourTable WHERE visible = 0 AND date <= '2021-07-27'),
SELECT MAX(date) FROM YourTable WHERE visible = 1 AND date <= '2021-07-27')
) as latest_not_visible;
Find the latest visible date earlier than the given date and count all rows in between those two dates:
SET #dt = '2021-07-25';
SELECT COUNT(*)
FROM t
WHERE date <= (SELECT date FROM t WHERE date = #dt AND visible = 0)
AND date > (SELECT date FROM t WHERE date < #dt AND visible = 1 ORDER BY date DESC LIMIT 1)
SQL Fiddle
A solution with GROUP_CONCAT():
SELECT CHAR_LENGTH(visible) - CHAR_LENGTH(TRIM(TRAILING '0' FROM visible)) latest_not_visible
FROM (
SELECT GROUP_CONCAT(visible ORDER BY date SEPARATOR '') visible
FROM tablename
WHERE date <= ?
) t
Change ? to the date you want.
See the demo.
You can use window functions:
select count(*)
from (select t.*,
max(case when visible = 1 then date end) over (order by date) as max_visible_date
from t
where date <= '2021-07-26' -- or whatever
) t
where visible = 0 and
(date > max_visible_date or max_visible_date is null);
Note that this version only mentions the date once. It also works for if there are no rows with visible = 1, and it works on any number of rows.

Display summary data for every month in SQL for last 3 years

I have this T-SQL query that would be the total count of claims, dollar value for the date declared.
But I need to find the count and dollar value for each month beginning starting 2016 and until today / yesterday. I want to load the result set to a new table. Any thoughts or suggestions? Thanks in advance!
T-SQL query
DECLARE #AsofDATE AS DATE
DECLARE #AsofDateINT AS INT
SET #AsofDATE = '1/1/2018'
SET #AsofDateINT = 20180101
SELECT
COUNT(S.ClaimNum) Count_of_Claims,
SUM(ReserveIndemnityAmount) AS RD_REserve,
#AsofDATE AS AsofDate
-- INTO #tempRD
FROM
(SELECT
f.*,
ROW_NUMBER() OVER (PARTITION BY ClaimNum ORDER BY f.ModifiedDate DESC) AS Row_order_desc
FROM
[dbo].[Snapshot] f
WHERE
CAST(f.ModifiedDate AS DATE) <= #AsofDATE) S
LEFT OUTER JOIN
(SELECT
ClaimKey, SUM( t.LossRsvAmt) AS ReserveIndemnityAmount
FROM
Stg.Claim_Transaction t
WHERE
TransactionDate < #AsofDateINT
GROUP BY
ClaimKey) T ON t.ClaimKey = s.ClaimID
WHERE
S.Row_order_desc = 1
AND S.DerivedClaimStatus NOT IN ('Closed', 'Cancelled', 'Abandoned', 'Record only', 'Opened in error' )
AND s.specialty = 'RD'
Current result:
Count_of_Claims RD_REserve AsofDate
-------------------------------------------------
15317 112192.15 2018-01-01
Expected result:
Count_of_Claims RD_REserve AsofDate
-------------------------------------------------
15317 112192.15 2017-01-12
15567 111592.15 2017-01-11
15356 15492.15 2017-01-10
Your AsofDate is hardcoded to return. Why not replace that with ModifiedDate?
so something like
select
count(s.claimnum) countofclaims
,sum(amount) amount
,cast(eomonth(modifieddate) as date) [asofdate]
from your query...
group by
cast(eomonth(modifieddate) as date)

Can I replace this loop in a sql server query

I have a list of items, sorted by date descending, and it checks them like this:
counted = 0
DateToCheck = now
foreach(item)
{
if( abs(item.date - DateToCheck) > 14 days )
{
counted++
}
DateToCheck = item.date
}
The goal is to get a count of items on the list that did not occur within 14 days of the previous item.
The table is just a list of dates, like this:
index ItemDate
307000 2017-08-17
307001 2017-04-25
307002 2016-09-23
307003 2016-08-26
307004 2016-04-30
307005 2016-03-01
307006 2016-03-01
The result here should be a count of 6, the last one is ignored since it is within 14 days of the one before.
You can use this query.
DECLARE #item TABLE([index] int, [date] DATETIME)
INSERT INTO #item
VALUES( 307006 ,'2017-08-17'),
(307005 ,'2017-04-25'),
(307004 ,'2016-09-23'),
(307003 ,'2016-08-26'),
(307002 ,'2016-04-30'),
(307001 ,'2016-03-01'),
(307000 ,'2016-03-01')
SELECT
count(*)
FROM #item T1
OUTER APPLY (
SELECT TOP 1 *
FROM #item T2
WHERE T2.[index] < T1.[index]
ORDER BY T2.[index] DESC) T
WHERE DATEDIFF(DAY, T.[date], T1.[date]) > 14
You can use this query if you do not have a ID column. Use ID column directly if you have one.
;WITH TBL AS (
SELECT ROW_NUMBER() OVER(ORDER BY ItemDate ASC) Id, ItemDate FROM TABLE_NAME
)
SELECT COUNT(a.ItemDate) FROM TBL a INNER JOIN TBL b ON b.ID = a.ID + 1 WHERE DATEDIFF(d, a.CreatedOn, b.CreatedOn) > 14;
With ID column, query changes to
SELECT COUNT(a.ItemDate) FROM TABLE_NAME a INNER JOIN TABLE_NAME b ON b.ID = a.ID + 1 WHERE DATEDIFF(d, a.CreatedOn, b.CreatedOn) > 14;

Date format not working in mysql procedure

{
delimiter &&
CREATE PROCEDURE `BPM_CLMBR_RPT_PROC` (IN customer_id INT,IN fromdate date,IN todate date)
BEGIN
-- distingushing the columns up,didntmove,down as well as group concatination
SELECT
RESPONSEDATE ,
ifnull(GROUP_CONCAT(CLIMBER, ''),0) AS 'up',
ifnull(GROUP_CONCAT(STATIC, ''),0) AS 'didntmove',
ifnull(GROUP_CONCAT(FALLER, ''),0) AS 'down',
ID
FROM
(
-- transposing the rows to column
SELECT
CASE
WHEN report = 'STATIC' THEN count
END AS 'STATIC',
CASE
WHEN report = 'CLIMBER' THEN count
END AS 'CLIMBER',
CASE
WHEN REPORT = 'FALLER' THEN COUNT
END AS 'FALLER',
RESPONSEDATE,
ID
FROM
(
-- counting the number of records in STATIC,CLIMBER,FALLER
SELECT
REPORT,RESPONSEDATE,COUNT(REPORT) count,ID
FROM (
-- grouping the records into STATIC,CLIMBER and FALLER
SELECT
CASE
WHEN (FNL.PREVIOUS_SCORE BETWEEN 0 AND 6 AND FNL.CURRENT_SCORE BETWEEN 0 AND 6) THEN 'STATIC'
WHEN (FNL.PREVIOUS_SCORE BETWEEN 7 AND 8 AND FNL.CURRENT_SCORE BETWEEN 7 AND 8) THEN 'STATIC'
WHEN (FNL.PREVIOUS_SCORE BETWEEN 9 AND 10 AND FNL.CURRENT_SCORE BETWEEN 9 AND 10) THEN 'STATIC'
WHEN (FNL.PREVIOUS_SCORE BETWEEN 0 AND 6 AND FNL.CURRENT_SCORE BETWEEN 7 AND 8) THEN 'CLIMBER'
WHEN (FNL.PREVIOUS_SCORE BETWEEN 0 AND 6 AND FNL.CURRENT_SCORE BETWEEN 9 AND 10) THEN 'CLIMBER'
WHEN (FNL.PREVIOUS_SCORE BETWEEN 7 AND 8 AND FNL.CURRENT_SCORE BETWEEN 9 AND 10) THEN 'CLIMBER'
WHEN (FNL.PREVIOUS_SCORE BETWEEN 7 AND 8 AND FNL.CURRENT_SCORE BETWEEN 0 AND 6) THEN 'FALLER'
WHEN (FNL.PREVIOUS_SCORE BETWEEN 9 AND 10 AND FNL.CURRENT_SCORE BETWEEN 0 AND 6) THEN 'FALLER'
WHEN (FNL.PREVIOUS_SCORE BETWEEN 9 AND 10 AND FNL.CURRENT_SCORE BETWEEN 7 AND 8) THEN 'FALLER'
END AS 'REPORT',
FNL.RESPONSEDATE,
ID
FROM (
SELECT
-- group concatination using space but only one client responses is expected
CLIENTID,
CLIENTNAME,
GROUP_CONCAT(TEMP.CURRENT_SCORE, '') AS 'CURRENT_SCORE',
GROUP_CONCAT(TEMP.PREVIOUS_SCORE, '') AS 'PREVIOUS_SCORE',
GROUP_CONCAT(TEMP.COMMENT,'') AS 'COMMENT',
max(id) ID,
max(responsedate) RESPONSEDATE
FROM
(
-- Top two npsscores are taken into account and only 1st comment is taken
SELECT
CLIENTID,id,CLIENTNAME,
CASE
WHEN RANK = 1 THEN npsscore
END AS 'CURRENT_SCORE',
CASE
WHEN RANK = 2 THEN npsscore
END AS 'PREVIOUS_SCORE',
CASE
WHEN RANK=1 THEN COMMENT
END AS 'COMMENT',
RESPONSEDATE
FROM
(
-- NPS_CLIENT_STATUS is calculated and only the 1st and 2nd rank holders are selected
SELECT
CLMBR_RPT.*,CASE
WHEN CLMBR_RPT.NPSSCORE BETWEEN 0 AND 6 THEN 'DETRACTOR'
WHEN CLMBR_RPT.NPSSCORE BETWEEN 7 AND 8 THEN 'PASSIVE'
ELSE 'PROMOTER'
END 'NPS_CLIENT_STATUS'
FROM
(
-- rank funtion is in corporated rownum() in Oracle
SELECT
a.*,
(CASE a.CLIENTID
WHEN #curType THEN #curRow:=#curRow + 1
ELSE #curRow:=1 AND #curType:=a.CLIENTID
END) AS rank
FROM
(SELECT
NSR.*
FROM
nps_summary_report NSR
INNER JOIN
-- innerjoin is done to get all the client id for a given date span which jas multiple records in the nps_summary_report table
-- joined with nps_summary_report table will eliminate all the records in the nps_summary_report table which is not having
-- customerid , multiple responses and date
-- this is the innermost query and will execute first and eliminate all the unwanted records
(SELECT
CLIENTID
FROM
nps_summary_report
WHERE CUSTOMERID=customer_id -- TO BE PROVIDED
-- AND RESPONSEDATE between STR_TO_DATE(fromdate, '%m/%d/%Y') AND STR_TO_DATE(todate, '%m/%d/%Y') -- TO BE PROVIDED
AND RESPONSEDATE > fromdate and RESPONSEDATE< todate -- TO BE PROVIDED
-- AND RESPONSEDATE BETWEEN date_format(STR_TO_DATE(#fromdate, '%m/%d/%Y'),'%Y-%m-%d') AND date_format(STR_TO_DATE(#todate, '%m/%d/%Y'),'%Y-%m-%d')
-- AND RESPONSEDATE BETWEEN date_format(#fromdate,'%Y-%m-%d') AND date_format(#todate,'%Y-%m-%d')
GROUP BY CLIENTID
HAVING COUNT(*) > 1) CLNT_ID ON CLNT_ID.CLIENTID = NSR.CLIENTID ) a, -- REMOVING ALL THE CLIENT WHICH HAVE 1 FEEDBACK
(SELECT #curRow:=0, #curType:='') r
WHERE CUSTOMERID=customer_id -- RETREIVE ALL DATA FOR BOOKMYSHOW ONLY
ORDER BY CLIENTID , RESPONSEDATE ) CLMBR_RPT
WHERE
CLMBR_RPT.RANK BETWEEN 0 AND 2)STG_BMS_CLIMBER_RPT
GROUP BY CLIENTID , CASE
WHEN RANK = 1 THEN npsscore
END , CASE
WHEN RANK = 2 THEN npsscore
END,CASE
WHEN RANK=1 THEN COMMENT
END
) TEMP
GROUP BY CLIENTID) FNL ) TBL
GROUP BY RESPONSEDATE,REPORT)stg_temp) TEMP
GROUP BY RESPONSEDATE
order by RESPONSEDATE desc;
END
&&
delimiter ; }
I am calling the stored procedure by
{ call BPM_CLMBR_RPT_PROC(6,str_to_date('2015-10-01','%Y-%m-%d'),str_to_date('2015-12-31','%Y-%m-%d')); }
The query is returning all the records irrespective of the date constraints .But when a hard coded value is passed inside the code like
{
RESPONSEDATE BETWEEN date_format(STR_TO_DATE('11/1/2015', '%m/%d/%Y'),'%Y-%m-%d') AND date_format(STR_TO_DATE('12/13/2015', '%m/%d/%Y'),'%Y-%m-%d')
}
then the expected result is comming.

JIRA : Issue status count for the past x (i.e 30 ) days

With below Query I able to see the count(no) of issues for all issueType in JIRA for a given date .
ie.
SELECT count(*), STEP.STEP_ID
FROM (SELECT STEP_ID, ENTRY_ID
FROM OS_CURRENTSTEP
WHERE OS_CURRENTSTEP.START_DATE < '<your date>'
UNION SELECT STEP_ID, ENTRY_ID
FROM OS_HISTORYSTEP
WHERE OS_HISTORYSTEP.START_DATE < '<your date>'
AND OS_HISTORYSTEP.FINISH_DATE > '<your date>' ) As STEP,
(SELECT changeitem.OLDVALUE AS VAL, changegroup.ISSUEID AS ISSID
FROM changegroup, changeitem
WHERE changeitem.FIELD = 'Workflow'
AND changeitem.GROUPID = changegroup.ID
UNION SELECT jiraissue.WORKFLOW_ID AS VAL, jiraissue.id as ISSID
FROM jiraissue) As VALID,
jiraissue as JI
WHERE STEP.ENTRY_ID = VALID.VAL
AND VALID.ISSID = JI.id
AND JI.project = <proj_id>
Group By STEP.STEP_ID;
the result is
Status Count
open 12
closed 13
..... ....
What I'd like to achieve is something like this actually ..where the total count for status open and closed for each day .
Date COUNT(Open) COUNT(Closed)
12-1-2012 12 1
13-1-2012 14 5
The general strategy would be this:
Select from a table of all the days in a month
LEFT OUTER JOIN your table that gets counts for each day
(left outer join being necessary in case there were no entries for that day, you'd want it to show a zero value).
So I think this is roughly what you need (not complete and date-function syntax is probably wrong for your db, but it will get you closer):
SELECT aDate
, COALESCE(SUM(CASE WHEN IssueStatus = 'whateverMeansOpen' THEN 1 END,0)) OpenCount
, COALESCE(SUM(CASE WHEN IssueStatus = 'whateverMeansClosed' THEN 1 END,0)) ClosedCount
FROM
(
SELECT DATEADD(DAY, I, #START_DATE) aDate
FROM
(
SELECT number AS I FROM [SomeTableWithAtLeast31Rows]
where number between 1 and 31
) Numbers
WHERE DATEADD(DAY, I, #START_DATE) < #END_DATE
) DateTimesInInterval
LEFT OUTER JOIN
(
Put your query here. It needs to output two columns, DateTimeOfIssue and IssueStatus
) yourHugeQuery ON yourHugeQuery.DateTimeOfIssue BETWEEN aDate and DATEADD(DAY, 1, aDate)
GROUP BY aDate
ORDER BY aDate