Get email frequency using grouping sets - tsql

I have a table with emails logs and need to check the email frequency. using grouping sets retrieve email count hourly, daily, weekly, monthly and yearly.
Can anyone send me an example.
Thank you !

SELECT DATEPART(yyyy,create_time) [year]
, DATEPART(mm,create_time) [month]
, DATEPART(WEEK,create_time) [week]
, DATEPART(dd,create_time) [day]
, DATEPART(hour,create_time) [hour]
, COUNT(*) AS c
FROM your_table
GROUP BY GROUPING SETS (DATEPART(yyyy,create_time)
,DATEPART(mm,create_time)
,DATEPART(WEEK,create_time)
,DATEPART(dd,create_time)
,DATEPART(hour,create_time))
ORDER BY [year], [month], [week], [day], [hour]
To group by multiple fields, just group columns in parentheses:
,(DATEPART(yyyy,create_time), DATEPART(mm,create_time))
Here's sample output, including the year/month grouping:
year month week day hour c
NULL NULL NULL NULL 0 12
NULL NULL NULL NULL 1 1
NULL NULL NULL 1 NULL 219
NULL NULL NULL 2 NULL 467
NULL NULL 1 NULL NULL 124
NULL NULL 2 NULL NULL 216
NULL 1 NULL NULL NULL 1899
NULL 2 NULL NULL NULL 1419
2015 NULL NULL NULL NULL 3750
2016 NULL NULL NULL NULL 7446
2015 8 NULL NULL NULL 391
2015 9 NULL NULL NULL 891

Thank you for the reply !
I have added ID column to the grouping sets,not getting if it is Hourly/weekly/daily/monthly generated.
SELECT ID, DATEPART(yyyy,create_time) [year]
, DATEPART(mm,create_time) [month]
, DATEPART(WEEK,create_time) [week]
, DATEPART(dd,create_time) [day]
, DATEPART(hour,create_time) [hour]
, COUNT(*) AS c
FROM your_table
GROUP BY GROUPING SETS(
(DATEPART(yyyy,create_time),ID)
,(DATEPART(mm,create_time),ID)
,(DATEPART(WEEK,create_time),ID)
,(DATEPART(dd,create_time),ID)
,(DATEPART(hour,create_time) ,ID))
ORDER BY [year], [month], [week], [day], [hour],ID
Result
Month Week Daily Hour C
NULL NULL NULL 0 12
NULL NULL NULL 0 471
NULL NULL NULL 0 176
NULL NULL NULL 0 145
NULL NULL NULL 0 633
NULL NULL NULL 0 13
NULL NULL NULL 0 24
NULL NULL NULL 0 2
NULL NULL NULL 0 324
NULL NULL NULL 0 555

Related

Replace calculated negative values with 0 in PostgreSQL

I have a table my_table:
case_id first_created last_paid submitted_time
3456 2021-01-27 2021-01-29 2021-01-26 21:34:36.566023+00:00
7891 2021-08-02 2021-09-16 2022-10-26 19:49:14.135585+00:00
1245 2021-09-13 None 2022-10-31 02:03:59.620348+00:00
9073 None None 2021-09-12 10:25:30.845687+00:00
6891 2021-08-03 2021-09-17 None
I created 2 new variables:
select *,
first_created-coalesce(submitted_time::date) as create_duration,
last_paid-coalesce(submitted_time::date) as paid_duration
from my_table;
The output:
case_id first_created last_paid submitted_time create_duration paid_duration
3456 2021-01-27 2021-01-29 2021-01-26 21:34:36.566023+00:00 1 3
7891 2021-08-02 2021-09-16 2022-10-26 19:49:14.135585+00:00 -450 -405
1245 2021-09-13 null 2022-10-31 02:03:59.620348+00:00 -412 null
9073 None None 2021-09-12 10:25:30.845687+00:00 null null
6891 2021-08-03 2021-09-17 null null null
My question is how can I replace new variables' value with 0, if it is smaller than 0?
The ideal output should look like:
case_id first_created last_paid submitted_time create_duration paid_duration
3456 2021-01-27 2021-01-29 2021-01-26 21:34:36.566023+00:00 1 3
7891 2021-08-02 2021-09-16 2022-10-26 19:49:14.135585+00:00 0 0
1245 2021-09-13 null 2022-10-31 02:03:59.620348+00:00 0 null
9073 None None 2021-09-12 10:25:30.845687+00:00 null null
6891 2021-08-03 2021-09-17 null null null
My code:
select *,
first_created-coalesce(submitted_time::date) as create_duration,
last_paid-coalesce(submitted_time::date) as paid_duration,
case
when create_duration < 0 THEN 0
else create_duration
end as QuantityText
from my_table
greatest(yourvalue,0)
Given yourvalue lower than 0, 0 will be returned as the greater value:
select *,
greatest(0,first_created-coalesce(submitted_time::date)) as create_duration,
greatest(0,last_paid-coalesce(submitted_time::date)) as paid_duration
from my_table
This will also change null values to 0.
case statement
If you wish to keep the null results, you can resort to a regular case statement. In order to alias your calculation you'll have to put it in a subquery or a cte:
select *,
case when create_duration<0 then 0 else create_duration end as create_duration_0,
case when paid_duration<0 then 0 else paid_duration end as paid_duration_0
from (
select *,
first_created-coalesce(submitted_time::date) as create_duration,
last_paid-coalesce(submitted_time::date) as paid_duration
from my_table ) as subquery;
(n+abs(n))/2
If you sum a number with its absolute value, then divide by two (average them out), you'll get that same number if it was positive, or you'll get zero if it was negative because a negative number will always balance itself out with its absolute value:
(-1+abs(-1))/2 = (-1+1)/2 = 0/2 = 0
( 1+abs( 1))/2 = ( 1+1)/2 = 2/2 = 1
select *,
(create_duration + abs(create_duration)) / 2 as create_duration_0,
(paid_duration + abs(paid_duration) ) / 2 as paid_duration_0
from (
select *,
first_created-coalesce(submitted_time::date) as create_duration,
last_paid-coalesce(submitted_time::date) as paid_duration
from my_table ) as subquery;
Which according to this demo, is slightly faster than case and about as fast as greatest(), without affecting null values.
Note that select * pulls everything from below, so you'll end up seeing create_duration as well as create_duration_0 - you can get rid of it by listing your desired output columns explicitly in the outer query. You can also rewrite it without subquery/cte, repeating the calculation, which will look ugly but in most cases planner will notice the repetition and make evaluate it only once
select *,
case when first_created-coalesce(submitted_time::date) < 0
then 0
else first_created-coalesce(submitted_time::date)
end as create_duration,
(abs(last_paid-coalesce(submitted_time::date))+last_paid-coalesce(submitted_time::date))/2 as paid_duration
from my_table ) as subquery;
or using a scalar subquery
select *,
(select case when a<0 then 0 else a end
from (select first_created-coalesce(submitted_time::date)) as alias(a) )
as create_duration,
(select case when a<0 then 0 else a end
from (select last_paid-coalesce(submitted_time::date)) as alias(a) )
as paid_duration
from my_table ) as subquery;
Neither of which help with anything in this case but are good to know.
If you are planning on attaching your SQL Database to an ASP.NET app, you could create a c# script to query your database, and use the following:
Parameters.AddWithValue(‘Data You want to change’ ‘0’);
However, if your not using your SQL database with a ASP.NET app, this will not work.

How can i get all rows from two tables Postgres

I have a problem with JOIN of two tables.
CREATE table appointment(
idappointment serial primary key,
idday int references days(idday),
worktime text
);
create table booking(
idbooking serial,
idappointment int references appointment(idappointment),
date date,
primary key(idappointment)
);
appointment
idappointment
idday
worktime
1
1
07:00-08:00
2
1
08:00-09:00
3
1
09:00-10:00
4
2
09:00-10:00
booking
idbooking
idappointment
date
1
1
2021-08-22
1
2
2021-08-2
And I want :
idbooking
idappointment
date
idbooking
idappointment
date
1
1
07:00-08:00
null
null
null
2
1
08:00-09:00
null
null
null
3
1
09:00-10:00
null
null
null
4
2
09:00-10:00
null
null
null
null
null
null
1
1
2021-08-22
null
null
null
1
2
2021-08-2
1
1
07:00-08:00
1
1
2021-08-22
2
1
08:00-09:00
1
2
2021-08-2
How can I get it ?

PIVOT not producing data on a single row

I am trying to write PIVOT to generate a row of data that originally sits as multiple rows in the DB. The DB data looks like this (appended)
txtSchoolID txtSubjectArchivedName intSubjectID intGradeID intGradeTransposeValue
95406288448 History 7 634 2
95406288448 History 7 635 2
95406288448 History 7 636 2
95406288448 History 7 637 2
95406288448 History 7 638 2
95406288448 History 7 639 2
95406288448 History 7 640 2
95406288448 History 7 641 2
95406288448 History 7 642 2
95406288448 History 7 643 2
What I want to get to is 1 row for each subject and SchoolID with the grades listed as columns.
I have written the following pivot:
SELECT intSubjectID, txtSchoolID, [636] AS Effort, [637] AS Focus, [638] AS Participation, [639] AS Groupwork, [640] AS Rigour, [641] AS Curiosity, [642] AS Initiative,
[643] AS SelfOrganisation, [644] as Perserverance
FROM (SELECT txtSchoolID, intReportTypeID, txtSubjectArchivedName, intSubjectID, intReportProgress, txtTitle, txtForename, txtPreName, txtMiddleNames,
txtSurname, txtGender, txtForm, intNCYear, txtSubmitByTitle, txtSubmitByPreName, txtSubmitByFirstname, txtSubmitByMiddleNames,
txtSubmitBySurname, txtCurrentSubjectName, txtCurrentSubjectReportName, intReportCycleID, txtReportCycleName, intReportCycleType,
intPreviousReportCycle, txtReportCycleShortName, intReportCycleTerm, intReportCycleAcademicYear, dtReportCycleStartDate,
dtReportCycleFinishDate, dtReportCyclePrintDate, txtReportTermName, dtReportTermStartDate, dtReportTermFinishDate,
intGradeID, txtGradingName, txtGradingOptions, txtShortGradingName, txtGrade, intGradeTransposeValue FROM VwReportsManagementAcademicReports) p
PIVOT
(MAX (intGradeTransposeValue)
FOR intGradeID IN ([636], [637], [638], [639], [640], [641], [642], [643], [644] )
) AS pvt
WHERE (intReportCycleID = 142) AND (intReportProgress = 1)
However, this is producing this
intSubjectID txtSchoolID Effort Focus Participation Groupwork Rigour Curiosity Initiative SelfOrganisation Perserverance
8 74001484142 NULL NULL NULL NULL NULL NULL NULL NULL NULL
8 74001484142 NULL NULL NULL NULL NULL 2 NULL NULL NULL
8 74001484142 3 NULL NULL NULL NULL NULL NULL NULL NULL
8 74001484142 NULL 2 NULL NULL NULL NULL NULL NULL NULL
8 74001484142 NULL NULL NULL 2 NULL NULL NULL NULL NULL
8 74001484142 NULL NULL NULL NULL NULL NULL 2 NULL NULL
8 74001484142 NULL NULL 2 NULL NULL NULL NULL NULL NULL
8 74001484142 NULL NULL NULL NULL NULL NULL NULL NULL 2
8 74001484142 NULL NULL NULL NULL 2 NULL NULL NULL NULL
8 74001484142 NULL NULL NULL NULL NULL NULL NULL 2 NULL
What I want is
intSubjectID txtSchoolID Effort Focus Participation Groupwork Rigour Curiosity Initiative SelfOrganisation Perserverance
8 74001484142 3 2 2 2 2 2 2 2 2
Is there a way to get it like this.
I have never tried a PIVOT before, this is my first time, so all help welcome.
I think the reason you got the unexpected result is you have so many unwanted columns in the Select in the sub-query and the pivot will group them, too.
Your query might be very close to your ideal result: try:
SELECT intSubjectID, txtSchoolID, [636] AS Effort, [637] AS Focus, [638] AS Participation, [639] AS Groupwork, [640] AS Rigour, [641] AS Curiosity, [642] AS Initiative,
[643] AS SelfOrganisation, [644] as Perserverance
FROM (SELECT txtSchoolID, intReportTypeID FROM VwReportsManagementAcademicReports) p --just these two
PIVOT
(MAX (intGradeTransposeValue)
FOR intGradeID IN ([636], [637], [638], [639], [640], [641], [642], [643], [644] )
) AS pvt
WHERE (intReportCycleID = 142) AND (intReportProgress = 1)
As per the comment above - the solution was:
try stripping the inner select down to only the columns that will be used in the pivot and are expected in the output. intSubjectID, txtSchoolID, intGradeTransposeValue, and intGradeID. all other columns will act as a grouping column in the output and can cause this type of non grouped output.
pivot can't return such what you asking for, but you can use another approach:
--test dataset
declare #test as table
( txtSchoolID bigint,
txtSubjectArchivedName varchar(10),
intSubjectID int,
intGradeID int,
intGradeTransposeValue int)
insert into #test
Values
(95406288448,'History',7,634,2),
(95406288448,'History',7,635,2),
(95406288448,'History',7,636,2),
(95406288448,'History',7,637,2),
(95406288448,'History',7,638,2),
(95406288448,'History',7,639,2),
(95406288448,'History',7,640,2),
(95406288448,'History',7,641,2),
(95406288448,'History',7,642,2),
(95406288448,'History',7,643,2)
--conditional aggregation
select intSubjectID,
txtSchoolID,
count(case when intGradeID = 636 then 1 end) AS Effort,
count(case when intGradeID = 637 then 1 end) AS Focus,
count(case when intGradeID = 638 then 1 end) AS Participation,
count(case when intGradeID = 639 then 1 end) AS Groupwork,
count(case when intGradeID = 640 then 1 end) AS Rigour,
count(case when intGradeID = 641 then 1 end) AS Curiosity,
count(case when intGradeID = 642 then 1 end) AS Initiative,
count(case when intGradeID = 643 then 1 end) AS SelfOrganisation,
count(case when intGradeID = 644 then 1 end) as Perserverance
from #test
group by intSubjectID, txtSchoolID
test is here

Ignore null values when using SQL Server 2012's Last_Value() function

I am using SQL Server 2012 and have a table of values that look like this. It is populated with event data.
FldType Date Price Size
--------------------------------------------
2 2012-08-22 00:02:01 9140 1048
0 2012-08-22 00:02:02 9140 77
1 2012-08-22 00:02:03 9150 281
2 2012-08-22 00:02:04 9140 1090
0 2012-08-22 00:02:05 9150 1
1 2012-08-22 00:02:06 9150 324
2 2012-08-22 00:02:07 9140 1063
I would like to track the lastest value for each of the 3 field types (0,1,2) so that the final output looks like this.
Date Price0 Size0 Price1 Size1 Price2 Size2
-----------------------------------------------------------------
2012-08-22 00:02:01 NULL NULL NULL NULL 9140 1048
2012-08-22 00:02:02 9140 77 NULL NULL 9140 1048
2012-08-22 00:02:03 9140 77 9150 281 9140 1048
2012-08-22 00:02:04 9140 77 9150 281 9140 1090
2012-08-22 00:02:05 9150 1 9150 281 9140 1090
2012-08-22 00:02:06 9150 1 9150 324 9140 1090
2012-08-22 00:02:07 9150 1 9150 324 9140 1063
Unfortunately, it is not ignoring subsequent null values so I get this instead.
Date Price0 Size0 Price1 Size1 Price2 Size2
-----------------------------------------------------------------
2012-08-22 00:02:01 NULL NULL NULL NULL 9140 1048
2012-08-22 00:02:02 9140 77 NULL NULL NULL NULL
2012-08-22 00:02:03 NULL NULL 9150 281 NULL NULL
2012-08-22 00:02:04 NULL NULL NULL NULL 9140 1090
2012-08-22 00:02:05 9150 1 NULL NULL NULL NULL
2012-08-22 00:02:06 NULL NULL 9150 324 NULL NULL
2012-08-22 00:02:07 NULL NULL NULL NULL 9140 1063
My current query looks like this
SELECT [Date],
LAST_VALUE(Price0) OVER (PARTITION BY FldType ORDER BY [Date] ) AS Price0,
LAST_VALUE(Size0) OVER (PARTITION BY FldType ORDER BY [Date]) AS Size0,
LAST_VALUE(Price1) OVER (PARTITION BY FldType ORDER BY [Date] ) AS Price1,
LAST_VALUE(Size1) OVER (PARTITION BY FldType ORDER BY [Date]) AS Size1,
LAST_VALUE(Price2) OVER (PARTITION BY FldType ORDER BY [Date] ) AS Price2,
LAST_VALUE(Size2) OVER (PARTITION BY FldType ORDER BY [Date]) AS Size2
FROM (
SELECT FldType, [Date], Price, Size,
CASE WHEN FldType = 0 THEN Price END as Price0,
CASE WHEN FldType = 0 THEN Size END as Size0,
CASE WHEN FldType = 1 THEN Price END as Price1,
CASE WHEN FldType = 1 THEN Size END as Size1,
CASE WHEN FldType = 2 THEN Price END as Price2,
CASE WHEN FldType = 2 THEN Size END as Size2
FROM [RawData].[dbo].[Events]
) as T1
ORDER BY [Date]
Is there some way to have SQL Server 2012 ignore null values when determining the lastest value? Or is there a better approach not using Last_Value() function?
To summarize I am trying to achieve two thing.
Split the Price and Size columns into 6 columns (2 columns x 3 field types)
Keep track of the latest value in each of these columns.
Any suggestions would be apprciated.
I'm not sure you can do it with LAST_VALUE, unless you add a PIVOT maybe.
Also, you need to treat Size and Price separately because they come from different rows. So, this achieves what you want be breaking it down.
DECLARE #source TABLE (FldType int, DateCol DateTime, Price int, Size int);
INSERT #source VALUES
(2, '2012-08-22 00:02:01', 9140, 1048),(0, '2012-08-22 00:02:02', 9140, 77),
(1, '2012-08-22 00:02:03', 9150, 281),(2, '2012-08-22 00:02:04', 9140, 1090),
(0, '2012-08-22 00:02:05', 9150, 1),(1, '2012-08-22 00:02:06', 9150, 324),
(2, '2012-08-22 00:02:07', 9140, 1063);
SELECT
S.DateCol, Xp0.Price0, Xs0.Size0, Xp1.Price1, Xs1.Size1, Xp2.Price2, Xs2.Size2
FROM
#source S
OUTER APPLY
(SELECT TOP 1 S0.Price AS Price0 FROM #source S0 WHERE S0.FldType = 0 AND S0.DateCol <= S.DateCol ORDER BY S0.DateCol DESC) Xp0
OUTER APPLY
(SELECT TOP 1 S1.Price AS Price1 FROM #source S1 WHERE S1.FldType = 1 AND S1.DateCol <= S.DateCol ORDER BY S1.DateCol DESC) Xp1
OUTER APPLY
(SELECT TOP 1 S2.Price AS Price2 FROM #source S2 WHERE S2.FldType = 2 AND S2.DateCol <= S.DateCol ORDER BY S2.DateCol DESC) Xp2
OUTER APPLY
(SELECT TOP 1 S0.Size AS Size0 FROM #source S0 WHERE S0.FldType = 0 AND S0.DateCol <= S.DateCol ORDER BY S0.DateCol DESC) Xs0
OUTER APPLY
(SELECT TOP 1 S1.Size AS Size1 FROM #source S1 WHERE S1.FldType = 1 AND S1.DateCol <= S.DateCol ORDER BY S1.DateCol DESC) Xs1
OUTER APPLY
(SELECT TOP 1 S2.Size AS Size2 FROM #source S2 WHERE S2.FldType = 2 AND S2.DateCol <= S.DateCol ORDER BY S2.DateCol DESC) Xs2
ORDER BY
DateCol;
The other way is to maintain a separate table via triggers or some ETL that does it the summary for you.

Right join on each row

Is there an easy way to do the following without having to recur to temporary tables or cursors?
“Table 1 right join Table 2, but for each row in Table 1.”
Eg:
Table 1, Row 1 right join Table 2.
Table 1, Row 2 right join Table 2.
Etc.
Thanks
Update 1
Sorry I should of explained in a bit more detail.
Table definitions:
Table1:
TABLE [dbo].[Table_1]
(
[id] [int],
[name] [nvarchar](max) NULL,
[id_table2] [int] NULL)
Table 2.
TABLE [dbo].[Table_2]
(
[id] [int] NOT NULL,
[code] [nvarchar](max) NULL, )
Table 1 data:
Table 1 Data:
1 Prov1 1
2 Prov2 2
NULL
NULL NULL
Table 2 data:
Table 2 Data:
1 01
2 02
3 03
4 04
5 05
NULL
NULL
If I do the following:
select * from Table_1 as t1
right join Table_2 as t2 on
t1.id_table2 =
t2.id
result:
1 Prov1 1 1 01
2 Prov2 2 2 02
NULL NULL NULL 3 03
NULL NULL NULL 4 04
NULL NULL NULL 5 05
Result I'd like:
"Right join on each table 1 row"
1 Prov1 1 1 01
1 Prov1 NULL 2 02
1 Prov1 NULL 3 03
1 Prov1 NULL 4 04
1 Prov1 NULL 5 05
2 Prov2 1 1 01
2 Prov2 NULL 2 02
2 Prov2 NULL 3 03
2 Prov2 NULL 4 04
2 Prov2 NULL 5 05
I think you should be looking for a CROSS JOIN instead of RIGHT JOIN.