CREATE TABLE #Temp(
Date datetime,
Flag bit)
#Temp table as data from 01-04-2019 to 31-04-2020 (366 records) and flag=0
DECLARE startdate date='12-04-2019', interval int =1 OR 3
Expected Result: If interval is 1 month, based on startdate, flag to be updated as 1 below records and rest for 0
date flag
01-04-2019 0
. 0
. 0
12-05-2019 1
. 0
. 0
12-06-2019 1
. 0
. 0
12-07-2019 1
.. 0
31-04-2020 0
If interval is 3 month, flag to be updated as 1 for quarter
date flag
01-04-2019 0
. 0
. 0
12-07-2019 1
. 0
. 0
12-10-2019 1
. 0
. 0
12-01-2020 1
. 0
31-04-2020 0
I am stuck trying get the result. I am using SQL Server 2017.
Took me awhile to realize that your dates were in different format than I'm used to.
I would go with a common table expression as opposed to a cursor. Besides that, consider the month difference between any given date and the start date. Take the modulo of that difference (that's what the '%' symbol is). If it's 0, then your interval has been hit and so activate your flag.
declare
#startdate date = '04.01.2019',
#interval int = 3; -- or 1, or whatever
with
dates as (
select #startdate dt, 1 flag
union all
select ap.nextDt,
flag =
case
when day(ap.nextDt) <> day(#startdate) then 0
when (month(ap.nextDt) - month(#startdate)) % #interval = 0 then 1
else 0
end
from dates
cross apply (select nextDt = dateadd(day,1,dt)) ap
where dt <= dateadd(year,1,#startdate)
)
select *
from dates
option (maxrecursion 367)
Related
I have a table with one column (TK) with multiple values, also duplicated and another one column with date.
I need to return a table with first column with distinct(TK) and the other columns like month.
I do an example into SQL FIDDLE
http://sqlfiddle.com/#!18/14cb9f/28
TK
JANUARY
open a
4
open B
4
TK
FEBRUARY
open a
4
open B
4
I need
TK
JANUARY
FEBRUARY
open a
4
4
open B
4
4
Thanks
A simple conditional aggregation should do the trick
SELECT TK
,Janary = sum( case when month(datastart)=1 then 1 else 0 end )
,February = sum( case when month(datastart)=2 then 1 else 0 end )
From TEST
Where year(datastart)=2021
Group By TK
Or you can use PIVOT
Select *
From (
Select TK
,Col = datename(month,DataStart)
,Val = 1
From TEST
Where year(datastart)=2021
) src
Pivot ( sum(Val) for Col in ([January] ,[February] ) ) pvt
There are multiple ways to do this, but avoiding sub-queries and making the syntax simple to read, this is the simplest I can get:
SELECT
TK,
SUM(
CASE WHEN DATASTART >= '2021-01-01' AND DATASTART < '2021-02-01' THEN 1 ELSE 0 END
) AS JENUARY,
SUM(
CASE WHEN DATASTART >= '2021-02-01' AND DATASTART <= '2021-02-28' THEN 1 ELSE 0 END
) AS FEBRUARY
FROM
Test
GROUP BY
TK
Check it out
http://sqlfiddle.com/#!18/14cb9f/34
This seems really simple but I can't figure it out, working in SQL Server. I have time series data and I want a column to track the state of ON/OFF events for each row, so when there's an ON event then the Desired Output column will have a 1 for each subsequent event until there is an OFF event. Please see example below. Thanks so much!
TimeStamp
Event
Desired Output
1:01
ON
1
1:02
OFF
0
1:04
other
0
1:05
other
0
1:06
ON
1
1:10
other
1
1:12
other
1
1:14
OFF
0
1:15
other
0
You can compare the cumulative count of ONs and OFFs:
select t.*,
(case when sum(case when event = 'ON' then 1 else 0 end) over (order by timestamp) >
sum(case when event = 'OFF' then 1 else 0 end)
then 1 else 0
end) as desired
from t;
WITH
flagged AS
(
SELECT
timestamp,
CASE WHEN event = 'ON' THEN 1
WHEN event = 'OFF' THEN 0 END AS state
FROM
#table
),
cumulative AS
(
SELECT
*,
COUNT(state) OVER (ORDER BY timestamp) AS state_group
FROM
flagged
)
SELECT
timestamp,
MAX(state) OVER (PARTITION BY state_group) AS persisted_state
FROM
cumulative
I realized there could actually be two ON events in a row, or sometimes entries can be missing. So to track the state of this event I think using a WHILE loop may be the best option.
WHILE #CurrentRow <= #TotalRows
BEGIN
SELECT #DesiredOutput = CASE WHEN Event = 'ON' THEN 1 ELSE CASE WHEN Event = 'OFF' THEN 0 ELSE #DesiredOutput END END
FROM #Table
WHERE #CurrentRow = Row_Number
UPDATE #Table
SET DesiredOutput = #DesiredOutput
WHERE #CurrentRow = Row_Number
SET #CurrentRow += 1
END
I have a table containing values from 12 different months
Table
{
January INT,
February INT,
etc.
}
and I need to sum values from specific months which numbers I keep in table (the number of months to sum can vary from 1 to 12):
DECLARE #Months TABLE
(
Number INT
)
so I'll surely need a big case and CTE but I don't really know how to achieve this.
The case statement isn't that bad:
select sum((case when m.month = 1 then Jan else 0 end) +
(case when m.month = 2 then Feb else 0 end) +
. . .
(case when m.month = 12 then Dec else 0 end)
)
from atable a cross join
#Months m;
You might want a group by as well. The above will return only one row for the entire table.
I need a little assistance in finishing this query. Here is what I have so far:
select
(select count(fileName)
from PDFFile
where dateTime > cast(getdate() as date)
and stateId = 17) AS "Files on SFTP"
,
(select count(fileName)
from PDFFile
where dateTime > cast(getdate() as date)
and stateId = 12) AS "Files Pass"
,
((select count(fileName)
from PDFFile
where dateTime > cast(getdate() as date)
and stateId = 17)
-
(select count(fileName)
from PDFFile
where dateTime > cast(getdate() as date)
and stateId = 12)) AS "Diff"
This is going to give me 3 columns of results. First result will be a number, second will be a number and the third will be the diff. There may even be a better way to write this but I'm still a novice. Hint: There is an entry in the DB for each state:
fileName |dateTime | stateID
--------+---------+-----------------+---------
abc.pdf | 2013-12-17 12:03:14.597 | 17
abc.pdf | 2013-12-17 12:06:23.096 | 12
xyz.pdf | 2013-12-17 12:09:16.583 | 17
xyz.pdf | 2013-12-17 12:10:19.823 | 12
Anyways for the finale...
I need to have a 4th column or a separate query (possible to UNION?) that pulls the fileNames based off the results in the diff.
Hypothetically if the diff is 40, the 4th column or separate query should list the 40 names. At times the diff may be negative so again hypothetically speaking if its -40 it should list the 40 names.
Assistance is greatly appreciated. Thank you!
You can greatly simplify your query using conditional aggregation:
select sum(case when dateTime > cast(getdate() as date) and stateId = 17 then 1 else 0
end) as "Files on SFTP",
sum(case when dateTime > cast(getdate() as date) and stateId = 12 then 1 else 0
end) AS "Files Pass",
(sum(case when dateTime > cast(getdate() as date) and stateId = 17 then 1 else 0
end) -
sum(case when dateTime > cast(getdate() as date) and stateId = 12 then 1 else 0
end)
) as diff
from PDFFile;
To get the list of files that are in the first group but not the second requires a bit more logic. The problem is that the unit of aggregation is at the file level.
select PDFFile
from PDFFile
group by PDFFile
having sum(case when dateTime > cast(getdate() as date) and stateId = 17 then 1 else 0
end) > 0 and
sum(case when dateTime > cast(getdate() as date) and stateId = 12 then 1 else 0
end) = 0;
Each part of the having clause counts the number of rows -- for each file -- that match the two conditions. You want at least one row that matches the first condition (hence > 0) and no rows that match the second (= 0).
This type of "combine row data into one column" question comes up quite a lot on Stack Overflow and although it has its place it's often easier and more efficient to solve the problem in another way.
For example, it's a lot easier to ask SQL to "give me all the filenames where stateid = 17", return them to your app and then get the app to display them. It may also be that your user doesn't want to see them until there is a particular summary line that is of interest to them that they need to drill down into further. Think of email as an example - you may only need to look at the 30 character subject line and know you don't need to download the 1Mb email body.
For your first question though there is a lot easier (and more efficient) way to write your query. Note that this example is untested
select
sum(case when stateId = 17 then 1 else 0 end) as "Files on SFTP",
sum(case when stateId = 12 then 1 else 0 end) as "Files Pass",
sum(case when stateId = 17 then 1 else 0 end) -
sum(case when stateId = 12 then 1 else 0 end) as "Diff",
from
PdfFile
where
datetime > getdate()
I'm using CASE here to prevent having to do three separate sub-queries. Sub-queries are inefficient. CASE isn't great but it's faster than sub-queries. I've also placed your datetime check at the bottom of the query as a WHERE as it was common to each of your checks.
I have a table in the following format (pseudo code):
CREATE TABLE [GLM_MASTER__BUDGET](
[Budget_Year],
[Budget_Type],
[Account],
[Period_1_Budget],
[Period_2_Budget],
[Period_3_Budget],
[Period_4_Budget],
[Period_5_Budget],
[Period_6_Budget],
[Period_7_Budget],
[Period_8_Budget],
[Period_9_Budget],
[Period_10_Budget],
[Period_11_Budget],
[Period_12_Budget]
)
I need to be able to query this with a with of a int for the current period like 6
This should return the the combined values of all periods from 1 to the number specified.
So I would end up with an output like this:
Budget_Year, Budget Type, Account, (Sum of all periods from 1 to the period specified) as Amount
I am using MS SQL server so it would be ok at the top to do something like:
DECLARE #current_period INT = 6
If you have the opportunity to redesign this table you may wish to consider it now.
You could use something along these lines:
DECLARE #current_period INT = 6
SELECT
Budget_Year, Budget Type, Account,
CASE WHEN #current_period >= 1 THEN [Period_1_Budget] ELSE 0 END +
CASE WHEN #current_period >= 2 THEN [Period_2_Budget] ELSE 0 END +
CASE WHEN #current_period >= 3 THEN [Period_3_Budget] ELSE 0 END +
CASE WHEN #current_period >= 4 THEN [Period_4_Budget] ELSE 0 END +
.....
..
CASE WHEN #current_period >= 12 THEN [Period_12_Budget] ELSE 0 END As Amount
FROM [GLM_MASTER__BUDGET]
Also it's not clear from your description whether you require a SUM and GROUP BY so I've left it out.