Is there possible query to compute for the total profits per category in 2 table? - mariadb

How do I do.
Here is the table 1 for payments
Payments
paymentid
Unit
branch
tenantid
name
amount
note
dateofpayment
1
Bodega
Santo
1
Alsace Alsace
10000
REFRESHED DATA
2022-12-27 16:22:53
2
Bodega
Santo
1
Alsace Alsace
1333
wawdad
2022-11-22 19:17:45
3
Bodega
Jacinto MRT
1
Alsace Alsace
1000
dwadawdaw
2023-01-01 19:36:13
4
Bodega
Jacinto MRT
4
awd awdawd
2000
awd
2022-12-25 15:45:49
Here is the table 2 for expenses
Expenses
expensesid
branch
typeofexpenses
amount
note
dateofexpenses
2
Santo
Electricity
299
aadadad
2022-12-27 00:00:00
3
Maligno
Electricity
20
daawd
2022-12-27 00:00:00
4
Santo
Electricity
11111
adawd
2022-12-27 00:00:00
5
Santo
Electricity
30
ef
2022-12-27 00:00:00
7
Santo
Electricity
100
we
2023-01-17 19:56:26
8
Santo
Electricity
200
dw
2022-12-25 15:45:49
and I want to get the total profit of this table per branch
here is the query I use:
SELECT payments.branch , SUM(payments.amount) AS Profits, SUM(expenses.amount) AS Expenses, SUM(payments.amount) - SUM(expenses.amount) AS Total
FROM payments
RIGHT OUTER JOIN expenses
on payments.branch = expenses.branch
GROUP BY payments.branch
I tried the above query but there result is like this:
Expected result
Branch
Payments
Expenses
Profit
Santo
11333
11740
-407
Jacinto MRT
3000
0
3000
Maligno
0
20
-20
IF YOU WANT TO TRY IT ON YOUR MACHINE HERE IS THE QUERY
CREATE TABLE `expenses` (
`expensesid` int(255) NOT NULL,
`branch` varchar(255) NOT NULL,
`typeofexpenses` varchar(255) NOT NULL,
`amount` int(255) NOT NULL,
`note` varchar(255) NOT NULL,
`dateofexpenses` datetime NOT NULL
);
INSERT INTO `expenses` (`expensesid`, `branch`, `typeofexpenses`, `amount`, `note`, `dateofexpenses`) VALUES
(2, 'Santo', 'Electricity', 299, 'aadadad', '2022-12-27 00:00:00'),
(3, 'Maligno', 'Electricity', 20, 'daawd', '2022-12-27 00:00:00'),
(4, 'Santo', 'Electricity', 11111, 'adawd', '2022-12-27 00:00:00'),
(5, 'Santo', 'Electricity', 30, 'ef', '2022-12-27 00:00:00'),
(7, 'Santo', 'Electricity', 100, 'we', '2023-01-17 19:56:26'),
(8, 'Santo', 'Electricity', 200, 'dw', '2022-12-25 15:45:49');
CREATE TABLE `payments` (
`paymentid` int(11) NOT NULL,
`Unit` varchar(255) NOT NULL,
`branch` varchar(255) NOT NULL,
`tenantid` int(11) NOT NULL,
`name` varchar(255) NOT NULL,
`amount` int(11) NOT NULL,
`note` varchar(255) NOT NULL,
`dateofpayment` datetime NOT NULL
);
INSERT INTO `payments` (`paymentid`, `Unit`, `branch`, `tenantid`, `name`, `amount`, `note`, `dateofpayment`) VALUES
(1, 'Bodega', 'Santo', 1, 'Alsace Alsace', 10000, 'REFRESHED DATA', '2022-12-27 16:22:53'),
(2, 'Bodega', 'Santo', 1, 'Alsace Alsace', 1333, 'wawdad', '2022-11-22 19:17:45'),
(3, 'Bodega', 'Jacinto MRT', 1, 'Alsace Alsace', 1000, 'dwadawdaw', '2023-01-01 19:36:13'),
(4, 'Bodega', 'Jacinto MRT', 4, 'awd awdawd', 2000, 'awd', '2022-12-25 15:45:49');

One way of doing this is to start with the full list of branches (subquery b) and then left join to the aggregated data of the other two tables (sub queries p & e) -
SELECT
b.branch AS Branch,
IFNULL(p.amount, 0) AS Payments,
IFNULL(e.amount, 0) AS Expenses,
IFNULL(p.amount, 0) - IFNULL(e.amount, 0) AS Profit
FROM (SELECT DISTINCT branch FROM expenses UNION SELECT DISTINCT branch FROM payments) AS b
LEFT JOIN (SELECT branch, SUM(amount) amount FROM payments GROUP BY branch) AS p ON b.branch = p.branch
LEFT JOIN (SELECT branch, SUM(amount) amount FROM expenses GROUP BY branch) AS e ON b.branch = e.branch;
As you are using MariaDB >= 10.2.1 we can use Common Table Expressions to improve readability. And as you have stated that you have a separate table for branches, I will assume branches (branchid, name) and branchid instead of branch in expenses and payments tables.
WITH payments AS (
SELECT branchid, SUM(amount) total FROM payments GROUP BY branchid
), expenses AS (
SELECT branchid, SUM(amount) total FROM expenses GROUP BY branchid
)
SELECT
b.name AS Branch,
IFNULL(p.total, 0) AS Payments,
IFNULL(e.total, 0) AS Expenses,
IFNULL(p.total, 0) - IFNULL(e.total, 0) AS Profit
FROM branches AS b
LEFT JOIN payments AS p ON b.branchid = p.branchid
LEFT JOIN expenses AS e ON b.branchid = e.branchid;

Related

How to get nearest DateTime from 2 tables

In SQLite, I want to build a query to get the nearest datetime for 'tag' entries against a 'tick' list:
CREATE TABLE Tick (
id integer primary key,
dt varchar(20)
);
INSERT INTO Tick (id, dt) VALUES
( 1, '2018-10-30 13:00:00'),
( 2, '2018-10-30 14:00:00'),
( 3, '2018-10-30 15:00:00'),
( 4, '2018-10-30 16:00:00'),
( 5, '2018-10-30 17:00:00'),
( 6, '2018-10-30 18:00:00'),
( 7, '2018-10-30 19:00:00'),
( 8, '2018-10-31 05:00:00'),
( 9, '2018-10-31 06:00:00'),
(10, '2018-10-31 07:00:00');
CREATE TABLE Tag (
id integer primary key,
dt varchar(20)
);
INSERT INTO Tag (id, dt) VALUES
(100, '2018-10-30 16:08:00'),
(101, '2018-10-30 17:30:00'),
(102, '2018-10-30 19:12:00'),
(103, '2018-10-31 04:00:00'),
(104, '2018-10-31 13:00:00');
The following query gives me the good match (based on diff) but I'm unable to get Tick columns:
SELECT Tag.dt,
(SELECT ABS(strftime('%s',Tick.dt) - strftime('%s',Tag.dt)) as diff
FROM Tick
ORDER BY diff ASC
LIMIT 1
) as diff from Tag
I tried the following but I receive an error on Tag.dt in ORDER BY:
SELECT
Tag.id, Tag.dt,
Tick.id, Tick.dt,
abs(strftime('%s',Tick.dt) - strftime('%s',Tag.dt)) as Diff FROM Tag JOIN Tick ON Tick.dt = (SELECT Tick.dt
FROM Tick
ORDER BY abs(strftime('%s',Tick.dt) - strftime('%s',Tag.dt)) ASC
limit 1)
The result I would like to have is something like:
TagID,DateTimeTag ,TickID,DateTimeTick
100,2018-10-30 16:08:00, 4,2018-10-30 16:00:00
101,2018-10-30 17:30:00, 6,2018-10-30 18:00:00
102,2018-10-30 19:12:00, 7,2018-10-30 19:00:00
103,2018-10-31 04:00:00, 8,2018-10-31 05:00:00
104,2018-10-31 13:00:00, 10,2018-10-31 07:00:00
Edited later...
Based on forpas's answer, I was able to derive something without using the ROW_COUNTER() keyword which I can't use in FME. I also set a maximum delta time difference (10000 sec) to find a match:
SELECT t.TagId, t.Tagdt, t.TickId, t.Tickdt, MIN(t.Diff)
FROM
(
SELECT
Tag.id as TagId, Tag.dt as Tagdt,
Tick.id as TickId, Tick.dt as Tickdt,
abs(strftime('%s',Tick.dt) - strftime('%s',Tag.dt)) as Diff
FROM Tag, Tick
WHERE Diff < 10000
) AS t
GROUP BY t.TagId
Thanks again!
Use ROW_NUMBER() window function:
SELECT t.tagID, t.tagDT, t.tickID, t.tickDT
FROM (
SELECT t.*,
ROW_NUMBER() OVER (PARTITION BY t.tagID, t.tagDT ORDER BY t.Diff) AS rn
FROM (
SELECT Tag.id tagID, Tag.dt tagDT, Tick.id tickID, Tick.dt tickDT,
ABS(strftime('%s',Tick.dt) - strftime('%s',Tag.dt)) as Diff
FROM Tag CROSS JOIN Tick
) AS t
) AS t
WHERE t.rn = 1
See the demo.
Rsults:
| tagID | tagDT | tickID | tickDT |
| ----- | ------------------- | ------ | ------------------- |
| 100 | 2018-10-30 16:08:00 | 4 | 2018-10-30 16:00:00 |
| 101 | 2018-10-30 17:30:00 | 5 | 2018-10-30 17:00:00 |
| 102 | 2018-10-30 19:12:00 | 7 | 2018-10-30 19:00:00 |
| 103 | 2018-10-31 04:00:00 | 8 | 2018-10-31 05:00:00 |
| 104 | 2018-10-31 13:00:00 | 10 | 2018-10-31 07:00:00 |
Create a temp_table query to get the differences of time stamps of the cross product of Tick and Tag tables and select the min value for each of the Tick table id s.
The two temp_table queries are identical.
Note that this query may not be efficient as it takes full cross product across the two tables
SELECT temp_table.tid, temp_table.tdt, temp_table.tiid, temp_table.tidt, temp_table.diff
FROM
(SELECT Tag.id AS tid, Tag.dt AS tdt, Tick.id AS tiid, Tick.dt AS tidt, abs(strftime('%s',Tick.dt) - strftime('%s',Tag.dt)) as diff
FROM tag, tick) temp_table
WHERE temp_table.diff =
(SELECT MIN(temp_table2.diff) FROM
(SELECT Tag.id AS tid, Tag.dt AS tdt, Tick.id AS tiid, Tick.dt AS tidt, abs(strftime('%s',Tick.dt) - strftime('%s',Tag.dt)) as diff
FROM tag, tick) temp_table2
WHERE temp_table2.tid = temp_table.tid
)
group by temp_table.tid

How to emulate window functions in MySQL < 8.0

I have tables like these:
INSERT INTO listings
(id, external_id, variation_id, product_id) VALUES
(101, '9900001', '9900001var1', 1),
(102, '9900001', '9900001var2', 4),
(103, '9900002', '9900002var1', 1),
(104, '9900002', '9900002var2', 2),
(105, '9900003', '9900003var1', 3),
(106, '9900003', '9900003var2', 4);
INSERT INTO products
(id, price) VALUES
(1, 101),
(2, 100),
(3, 100),
(4, 102);
Which means that there are 3 listings (9900001, 9900002, 9900003) with 2 products each (1, 4), (1, 2) and (3, 4) respectively.
What I need is to retrieve one single row for each listing, with the id (not the price) of the product with the highest price in that listing.
So, the desired output would be:
id | external_id | variation_id | product_id
[ANY] 9900001 [ANY] 4
[ANY] 9900002 [ANY] 1
[ANY] 9900003 [ANY] 4
The closest I got to the desired answer was with this query:
SELECT
p.id AS product_id_max,
p.price AS product_price_max,
MAX(p.price) AS product_price_max_max,
listings.*
FROM listings
INNER JOIN (
-- Subquery tested above:
SELECT DISTINCT pp3.* FROM
(SELECT MAX(p2.price) as max_price
FROM products p2
INNER JOIN listings l2 ON l2.product_id = p2.id
GROUP BY l2.external_id) pp2
INNER JOIN
(SELECT p3.* FROM products p3 ) pp3
ON
pp2.max_price = pp3.price
ORDER BY pp3.price DESC
) AS p
ON p.id = listings.product_id
-- WHERE MAX(p.price) = p.price
GROUP BY external_id
-- HAVING MAX(p.price) = p.price
ORDER BY product_price_max DESC
Uncommenting the WHERE clause throws an error, uncommenting the HAVING clause returns less rows than desired. Leavin both commented give the correct rows but wrong values in the product_id column.
Fiddle: http://sqlfiddle.com/#!9/d58d665/54/0
I figured it out:
SELECT
listings.*,
max_p.product_id AS max_product_id
FROM listings
INNER JOIN (
SELECT DISTINCT max_external_id as external_id, pp3.id as product_id FROM
(SELECT MAX(p2.price) as max_price, l2.external_id as max_external_id
FROM products p2
INNER JOIN listings l2 ON l2.product_id = p2.id
GROUP BY l2.external_id) pp2
INNER JOIN
(SELECT p3.* FROM products p3 ) pp3
ON
pp2.max_price = pp3.price
ORDER BY pp3.price DESC
) AS max_p
ON max_p.external_id = listings.external_id
GROUP BY listings.external_id
As tested here:
http://sqlfiddle.com/#!9/d58d665/53/0

Oracle Query on 3 tables with 2 outer joins

I'm having some trouble writing a query that seems like it should be simple, but the solution is evading me.
We have three tables (simplified for the purpose of this question):
persons - a table of user names:
per_id number(10) - primary key, populated by a sequence
user_name varchar2(50)
user_id varchar2(15) - unique, basically the employee ID
work_assignments - kind of like crew assignments, but more general:
wa_id number(10) - primary key, populated by a sequence
wa_name varchar2(25)
current_assignments - which users have which work_assignments; the average per user is about 25 work assignments, but some "lucky" individuals have upwards of 150:
wa_id number(10)
per_id number(10)
I'm trying to write a query that will compare the work_assignments for two users, in a total of three columns. The results should look like this:
WA_Name User_Name1 User_Name2
Crew A Bob Joe
Crew B Joe
Crew C Bob
Basically, every work_assignment that either of the two user has, with the name(s) of the user(s) who has it.
Here's the closest I could come up with (well, I did come up with an ugly query with 3 subqueries that does the job, but it seems like there should be a more elegant solution):
select distinct * from (
select wa.name work_assignment,
per.name user_name1,
per2.name user_name2
from work_assignments wa join current_assignments ca on wa.wa_id = ca.wa_id
join current_assignments ca2 on wa.wa_id = ca2.wa_id
left outer join persons per on per.per_id = ca.per_id and per.user_id = 'X12345'
left outer join persons per2 on per2.per_id = ca2.per_id and per2.user_id = 'Y67890'
)
where user_name1 is not null or user_name2 is not null
order by 1;
The problem with this one is that if both users have a work assignment, it shows 3 records: one for Bob, one for Joe, and one for both:
WA_Name User_Name1 User_Name2
Crew A Bob Joe
Crew A Joe
Crew A Bob
Please help!
Thanks,
Dan
I created a set of sample data/tables
drop table persons;
drop table work_assgn;
drop table curr_assgn;
create table persons(
per_id number(10) not null
, user_name varchar2(10) not null
, user_id varchar2(10) not null
)
;
insert into persons values( 1, 'Bob', 'X123' );
insert into persons values( 2, 'Joe', 'Y456' );
insert into persons values( 3, 'Mike', 'Z789' );
insert into persons values( 4, 'Jeff', 'J987' );
commit;
create table work_assgn(
wa_id number(10) not null
, wa_name varchar2(25)
)
;
insert into work_assgn values( 10, 'Crew A' );
insert into work_assgn values( 20, 'Crew B' );
insert into work_assgn values( 30, 'Crew C' );
insert into work_assgn values( 40, 'Crew D' );
commit;
create table curr_assgn(
wa_id number(10) not null
, per_id number(10) not null
)
;
insert into curr_assgn values( 10, 1 );
insert into curr_assgn values( 10, 2 );
insert into curr_assgn values( 20, 2 );
insert into curr_assgn values( 30, 1 );
insert into curr_assgn values( 40, 4 );
commit;
select * from persons;
select * from work_assgn;
select * from curr_assgn;
So the data looks like
PERSONS
PER_ID USER_NAME USER_ID
---------- ---------- ----------
1 Bob X123
2 Joe Y456
3 Mike Z789
4 Jeff J987
WORK_ASSGN
WA_ID WA_NAME
---------- -------------------------
10 Crew A
20 Crew B
30 Crew C
40 Crew D
CURRASSGN
WA_ID PER_ID
---------- ----------
10 1
10 2
20 2
30 1
40 4
One approach may be to use a PIVOT
with assignment as
(
select p.user_id, p.user_name, a.wa_name
from persons p
join curr_assgn c
on p.per_id =c.per_id
join work_assgn a
on a.wa_id = c.wa_id
where p.user_id in ( 'X123', 'Y456' )
)
select * from assignment
pivot
( max(user_name) for user_id in ( 'X123', 'Y456' )
)
;

Get the most recent record for each user where value is 'K', action id is null or its state is 1

I have the following tables in SQL Server:
user_id, value, date, action_id
----------------------------------
1 A 1/3/2012 null
1 K 1/4/2012 null
1 B 1/5/2012 null
2 X 1/3/2012 null
2 K 1/4/2012 1
3 K 1/3/2012 null
3 L 1/4/2012 2
3 K 1/5/2012 3
4 K 1/3/2012 null
action_id, state
----------------------------------
1 0
2 1
3 1
4 0
5 1
I need to return the most recent record for each user where the value is 'K', the action id is either null or its state is set to 1. Here's the result set I want:
user_id, value, date, action_id
----------------------------------
3 K 1/5/2012 3
4 K 1/3/2012 null
For user_id 1, the most recent value is B and its action id is null, so I consider this the most recent record, but it's value is not K.
For user_id 2, the most recent value is K, but action id 1 has state 0, so I fallback to X, but X is not K.
user_id 3 and 4 are straightforward.
I'm interested in Linq to SQL query in ASP.NET, but for now T-SQL is fine too.
The SQL query would be :
Select Top 1 T1.* from Table1 T1
LEFT JOIN Table2 T2
ON T1.action_id = T2.action_id
Where T1.Value = 'K' AND (T1.action_id is null or T2.state = 1)
Order by T1.date desc
LINQ Query :
var result = context.Table1.Where(T1=> T1.Value == "K"
&& (T1.action_id == null ||
context.Table2
.Where(T2=>T2.State == 1)
.Select(T2 => T2.action_id).Contains(T1.action_id)))
.OrderByDescending(T => T.date)
.FirstOrDefault();
Good Luck !!
This query will return desired result set:
SELECT
*
FROM
(
SELECT
user_id
,value
,date
,action_id
,ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY date DESC) RowNum
FROM
testtable
WHERE
value = 'K'
) testtable
WHERE
RowNum = 1
You can also try following approach if user_id and date combination is unique
Make sure to get the order of predicates in the join to be able to use indexes:
SELECT
testtable.*
FROM
(
SELECT
user_id
,MAX(date) LastDate
FROM
testtable
WHERE
value = 'K'
GROUP BY
user_id
) tblLastValue
INNER JOIN
testtable
ON
testtable.user_id = tblLastValue.user_id
AND
testtable.date = tblLastValue.LastDate
This would select the top entries for all users as described in your specification, as opposed to TOP 1 which just selects the most recent entry in the database. I'm assuming here that your tables are named users and actions:
WITH usersactions as
(SELECT
u.user_id,
u.value,
u.date,
u.action_id,
ROW NUMBER() OVER (PARTITION BY u.user_id ORDER BY u.date DESC, u.action_id DESC) as row
FROM users u
LEFT OUTER JOIN actions a ON u.action_id = a.action_id
WHERE
u.value = 'K' AND
(u.action_id IS NULL OR a.state = 1)
)
SELECT * FROM usersactions WHERE row = 1
Or if you don't want to use a CTE:
SELECT * FROM
(SELECT
u.user_id,
u.value,
u.date,
u.action_id,
ROW NUMBER() OVER (PARTITION BY u.user_id ORDER BY u.date DESC, u.action_id DESC) as row
FROM users u
LEFT OUTER JOIN actions a ON u.action_id = a.action_id
WHERE
u.value = 'K' AND
(u.action_id IS NULL OR a.state = 1)
) useractions
WHERE row = 1

How to come up with statistics that shows the total number of quizzes, total number of participants?

I am developing a simple web application that provides the users with quizzes. since I am new to ASP.NET world, I am following the How to build Quiz Engine Video series on ASP.net website. My database design is to similar to the design used in these videos.
This is the link of the first video:
Everything works fine with me, but I want now to develop a query that helps me to display a statistics to the Admin which shows:
Total number of quizzes in the system
Total number of participants in each quiz
Total number of participants in general in daily basis, weekly basis, monthly basis and yearly basis (if possible)
To clarify the last point, I want the admin to see the following:
total number of participant druing last week was: ......
total number of taken quizzes during last week was: .........
total number of taken quizzes during last month was: .........
I think something like this is very useful to know the usage of the system and to show the management how the system is efficient in the copmany.
The sechma of the database:
CREATE TABLE [dbo].[Quiz](
[QuizID] [int] IDENTITY(1,1) NOT NULL,
[Title] [varchar](max) NOT NULL,
[Description] [varchar](max) NULL,
CONSTRAINT [PK_Quiz] PRIMARY KEY CLUSTERED
(
[QuizID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
SET IDENTITY_INSERT [dbo].[Quiz] ON
INSERT [dbo].[Quiz] ([QuizID], [Title], [Description]) VALUES (6, N'Safety', N'General Safety Test')
INSERT [dbo].[Quiz] ([QuizID], [Title], [Description]) VALUES (7, N'my title', N'my description')
INSERT [dbo].[Quiz] ([QuizID], [Title], [Description]) VALUES (9, N'General Safety Quiz2', N'Testing')
INSERT [dbo].[Quiz] ([QuizID], [Title], [Description]) VALUES (10, N'General Safety Quiz3', N'Testing #2')
SET IDENTITY_INSERT [dbo].[Quiz] OFF
/****** Object: Table [dbo].[Question] Script Date: 11/17/2011 00:44:38 ******/
CREATE TABLE [dbo].[Question](
[QuestionID] [int] IDENTITY(1,1) NOT NULL,
[Question] [varchar](max) NOT NULL,
[Answer1] [varchar](max) NOT NULL,
[Answer2] [varchar](max) NOT NULL,
[Answer3] [varchar](max) NOT NULL,
[Answer4] [varchar](max) NOT NULL,
[CorrectAnswer] [tinyint] NOT NULL,
[AnswerExplanation] [varchar](max) NULL,
[QuestionOrder] [tinyint] NOT NULL,
[QuizID] [int] NOT NULL,
CONSTRAINT [PK_Question] PRIMARY KEY CLUSTERED
(
[QuestionID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
SET IDENTITY_INSERT [dbo].[Question] ON
INSERT [dbo].[Question] ([QuestionID], [Question], [Answer1], [Answer2], [Answer3], [Answer4], [CorrectAnswer], [AnswerExplanation], [QuestionOrder], [QuizID]) VALUES (4, N'What is your name?', N'Mohammed ', N'Ali', N'Hassan', N'Husain', 1, N'My Name', 1, 6)
INSERT [dbo].[Question] ([QuestionID], [Question], [Answer1], [Answer2], [Answer3], [Answer4], [CorrectAnswer], [AnswerExplanation], [QuestionOrder], [QuizID]) VALUES (7, N'What is the definition of Safety?', N'Being Safe', N'Being in danger', N'Be careful', N'be careless', 1, N'Nothing', 1, 9)
INSERT [dbo].[Question] ([QuestionID], [Question], [Answer1], [Answer2], [Answer3], [Answer4], [CorrectAnswer], [AnswerExplanation], [QuestionOrder], [QuizID]) VALUES (8, N'What is the definition of Safety? ', N'Being Safe', N'Being Careless', N'Being Careful', N'Being in Dangerous', 1, N'Nothing to say', 1, 10)
SET IDENTITY_INSERT [dbo].[Question] OFF
/****** Object: Table [dbo].[UserQuiz] Script Date: 11/17/2011 00:44:38 ******/
CREATE TABLE [dbo].[UserQuiz](
[UserQuizID] [int] NULL,
[QuizID] [int] NOT NULL,
[DateTimeComplete] [smalldatetime] NOT NULL,
[Score] [tinyint] NOT NULL,
[Username] [nvarchar](256) NOT NULL
) ON [PRIMARY]
GO
INSERT [dbo].[UserQuiz] ([UserQuizID], [QuizID], [DateTimeComplete], [Score], [Username]) VALUES (NULL, 6, CAST(0x9F8F02D8 AS SmallDateTime), 100, N'SMP\ALMARHMS')
INSERT [dbo].[UserQuiz] ([UserQuizID], [QuizID], [DateTimeComplete], [Score], [Username]) VALUES (NULL, 6, CAST(0x9F8F02E3 AS SmallDateTime), 50, N'SMP\ALMARHMS')
INSERT [dbo].[UserQuiz] ([UserQuizID], [QuizID], [DateTimeComplete], [Score], [Username]) VALUES (NULL, 6, CAST(0x9F8F0333 AS SmallDateTime), 50, N'SMP\ALMARHMS')
INSERT [dbo].[UserQuiz] ([UserQuizID], [QuizID], [DateTimeComplete], [Score], [Username]) VALUES (NULL, 7, CAST(0x9F8F0335 AS SmallDateTime), 100, N'SMP\ALMARHMS')
By help from one of the guys here in this great community, I came up with one query that shows the number of participants in each quiz. This is the query:
SELECT Q.QuizID, Q.Title, COUNT(*) AS Users
FROM dbo.UserQuiz AS UQ
INNER JOIN dbo.Quiz AS Q ON Q.QuizID = UQ.QuizID
GROUP BY Q.QuizID, Q.Title
Now I need to modify it or to come up withe new query that gives me the above three points. How can I do that?
If you want to count for the last 7 days and the last 30 days, you could use something like this:
-- Count of Participants in the last 7 days
SELECT COUNT(DISTINCT Q.UserName)
FROM dbo.UserQuiz Q
WHERE DateTimeComplete >= DATEADD(dd, -7, DATEADD(day, DATEDIFF(day, 0, GETDATE()), 0))
-- Count quizzes taken in the last 7 days
SELECT COUNT(Q.QuizID)
FROM dbo.UserQuiz Q
WHERE Q.DateTimeComplete >= DATEADD(dd, -7, DATEADD(day, DATEDIFF(day, 0, GETDATE()), 0))
-- Count quizzes taken in the last 30 days
SELECT COUNT(Q.QuizID)
FROM dbo.UserQuiz Q
WHERE Q.DateTimeComplete >= DATEADD(dd, -30, DATEADD(day, DATEDIFF(day, 0, GETDATE()), 0))
Note that if you want to count for calendar weeks and calendar months then you need to do a bit more work to filter the proper starting and ending date filters.
EDIT: Fixed the query syntax (1st answer posted without running it in SSMS) also I didn't notice at first that the UserQuiz.UserQuizID is nullable. This column is therefore not what I would have expected it to be.
EDIT #2: As per OP's request, these three statistics can also be retrieved in a single query using sub-selects. Sub-selects are necessary because of differences in either the filter criteria or the aggregations involved in counting each statistic (or both).
-- Combine three stats into one query using sub-selects...
SELECT
(SELECT COUNT(DISTINCT Q.UserName)
FROM dbo.UserQuiz Q
WHERE DateTimeComplete >= DATEADD(dd, -7, DATEADD(day, DATEDIFF(day, 0, GETDATE()), 0)))
as ParticipantsLast7Days,
(SELECT COUNT(Q.QuizID)
FROM dbo.UserQuiz Q
WHERE Q.DateTimeComplete >= DATEADD(dd, -7, DATEADD(day, DATEDIFF(day, 0, GETDATE()), 0)))
as QuizzesLast7Days,
(SELECT COUNT(Q.QuizID)
FROM dbo.UserQuiz Q
WHERE Q.DateTimeComplete >= DATEADD(dd, -30, DATEADD(day, DATEDIFF(day, 0, GETDATE()), 0)))
as QuizzesLast30Days

Resources