Selecting data by year, month and week from table - mysql

I have the following tables:
Table: promotion_asset
promotion_id
asset_id
(a promotion can have many assets)
Table: promotion_tracking
id(PK)
asset_id
date_scanned
(logging table for every time an asset is scanned )
I want to TRY in one query to be able to identify how many times assets in a specific promotion ID, have been scanned: this year, this month, and this week.
i've tried lots of different methods but cannot find a single query that returns the correct results.

I only have sql server, so I was able to test this for the Year and Month functions, looked up the WeekOfYear for mysql
SELECT pa.promotion_id
, SUM(CASE
WHEN YEAR(pt.date_scanned) = YEAR(GETDATE()) THEN 1
ELSE 0
END CASE) AS ThisYear
, SUM(CASE
WHEN YEAR(pt.date_scanned) = YEAR(GETDATE())
AND MONTH(pt.date_scanned) = MONTH(GETDATE()) THEN 1
ELSE 0
END CASE) AS ThisMonth
, SUM(CASE
WHEN WEEKOFYEAR(pt.date_scanned) = WEEKOFYEAR(GETDATE()) THEN 1
ELSE 0
END CASE) AS ThisWeek
FROM promotion_tracking AS pt
INNER JOIN promotion_asset AS pa ON pt.asset_id = pa.asset_id
GROUP BY pa.promotion_id

Related

Mysql - most efficient way to retrieve data based on multiple selects and wheres

I'm having trouble finding the most efficient way of retrieving various different sumed values from a Mysql table.
Let's say I've got 4 columns - userid, amount, paid, referral.
I'd like to retrieve the following based on a user id:
1 - the sum of amount that is paid (marked as 1)
2 - the sum of amount that is unpaid (marked as 0)
3 - the sum of amount that is paid and referral (marked as 1 on both paid and referral columns)
4 - the sum of amount that unpaid and referral (marked as 0 on paid and 1 on referral columns)
I've tried an embedded select statement like this:
SELECT (
SELECT sum(payout)
FROM table1
WHERE ispaid = 0 and userid = '100'
) AS unpaid
(
SELECT sum(payout)
FROM table1
WHERE ispaid = 1 and userid = '100'
) AS paid,
(
SELECT sum(payout)
FROM table1
WHERE ispaid = 0 and isreferral = 1 and userid = '100'
) AS refpending,
(
SELECT sum(payout)
FROM table1
WHERE ispaid = 1 and isreferral = 1 and userid = '100'
) AS refpaid
This works, but its slow (or at least feels like it could be quicker) on my server, around 1.5 seconds.
I'm sure there is a better way of doing this with a group statement but can't get my head around it!
Any help is much appreciated.
Thanks
You can use conditional expressions inside SUM():
SELECT
SUM(CASE WHEN ispaid=0 THEN payout END) AS unpaid,
SUM(CASE WHEN ispaid=1 THEN payout END) AS paid,
SUM(CASE WHEN ispaid=0 AND isreferral=1 THEN payout END) AS refpending,
SUM(CASE WHEN ispaid=0 AND isreferral=1 THEN payout END) AS refpaid
FROM table1
WHERE userid = '100'
If a given row is not matched by any CASE...WHEN clause, then the value of the expression is NULL, and SUM() ignores NULLs. You could also have an ELSE 0 clause in there if you want to be more explicit, since SUM() will not be increased by a 0.
Also make sure you have an index on userid in this table to select only the rows you need.

Calculate total sales without missing values while joining two tables

I have a query
I have to calculate monthly sales per branch and customer (Data coming from one table)
Data should look like below
I can write the query for Jan_2019 total sales:
I create a temp table for Feb_2019. I can use the join and combine the 2 tables, but in Feb_2019 if there are new customers added, then when joining the tables I am missing new customers, and due to this the total sales for that month are not matching.
Can any one help?
I have written the query like this below
;with a as
(
select branchid, customer, sum(totalsales) as jan_totalsales from tableA
where year = 2019 and month = 1
group by customer, branched
), feb as
(
select branchid, customer, sum(totalsales) as feb_totalsales from tableA
where year = 2019 and month = 2
group by customer, branched
)
select a.branchid, feb.branchid, a.jan_totalsales, feb.feb_totalsales
from a
left join feb on feb.branchid = a.branchid
I have to create this in a temp table and do it for march_2019
Again, I am not getting new customers as I am joining from Jan data.
Can anyone help me to make this simple?
What you are after here is a conditional aggregate. This should get you on the right path:
SELECT branchid,
customer,
SUM(CASE WHEN [Year] = 2019] AND [Month] = 1 THEN totalsales ELSE 0 END) AS JanSales,
SUM(CASE WHEN [Year] = 2019] AND [Month] = 2 THEN totalsales ELSE 0 END) AS FebSales,
....
FROM YourTable
GROUP BY branchid,
customer;
If you don't undertstand how this works, please do ask. At the end of the day, it's you who has to support the SQL, not myself or other volunteers on Stack Overflow.

SQL How to create a value for a new column based on the count of an existing column by groups?

I have a temp table that I'm reading from, and I want to look at one of the columns that only has two grade values - either a 3 or a 4 and build two new columns - one that holds the count of the 3's and the other to hold the count of the 4's - by a particular grouping. My code looks like this.
Select Max(Counting) as Total
, student
, stdType
, Score3 = (SELECT count(*) from #tempBWMSHonors3 where score = '3')
, Score4 = (SELECT count(*) from #tempBWMSHonors3 where score = '4')
from #tempBWMSHonors3
group by student, stateID, grade, stdType
I also embedded an image that show an example of my temp table and what I'm trying to achieve (as well as the result I am getting - but don't want).
[]
I think you just want conditional aggregation, not subqueries:
select Max(Counting) as Total, student, stdType,
sum(case when score = '3' then 1 else 0 end) as Score3,
sum(case when score = '4' then 1 else 0 end) as Score4
from #tempBWMSHonors3
group by student, stdType;
Note: if score is a number and not a string, then you should not use single quotes for the constant.

Count DISTINCT on a single column over multiple conditions

I have a table, and I want to get the DISTINCT count of usernames over a certain period of time. Currently I'm running this query
SELECT DISTINCT username FROM user_activity WHERE company_id = 9 AND timestamp BETWEEN '2015-09-00' AND '2015-10-01' AND action = "Login Success";
It works great, however, I have multiple Companies that I want to select the count for. How do I expand the previous query to show me the distinct counts for multiple companies?
select count(distinct username),
sum(case when company_id = 1 then 1 else 0 end) A,
sum(case when company_id = 9 then 1 else 0 end) B
from `user_activity` Where timestamp BETWEEN '2015-09-00' AND '2015-10-01' AND action = "Login Success"
I've done something like this, however, I'm not getting the correct numbers. Ideally I would like to list each count as a different value for ease of reading, like the previous query illustrates. I don't need the count(distinct username) column to appear in my result, just the conditionals.
Thanks in advance.
If you don't mind two rows instead of two columns:
SELECT company_id, COUNT(DISTINCT username)
FROM user_activity
WHERE company_id IN (1,9)
AND timestamp >= '2015-09-01'
AND timestamp < '2015-09-01' + INTERVAL 1 MONTH
AND action = "Login Success"
GROUP BY company_id

same (sub)query multiple time in a mysql query

I have a mysql query like the following.
select new,processing,close
from
(select count(id) new from tickets where id_client in (_a_list_of_client_id) and status = new),
(select count(id) processing from tickets where id_client in (_a_list_of_client_id) and status = processing),
(select count(id) close from tickets where id_client in (_a_list_of_client_id) and status = close)
The following is not the exact query but a pseudo query
here _a_list_of_client_id is another query like following
select id_client from client where id_user = {some_id_given_as_parameter}
I just wondering is this the right approach to use same subquery multiple times in a query. Or is there any other way to do things like this.
Thanks in advance
M H Rasel
You can use sum with case and move the subquery to the where criteria:
select
sum(case when status = 'new' then 1 else 0 end) new,
sum(case when status = 'processing' then 1 else 0 end) processing,
sum(case when status = 'close' then 1 else 0 end) close
from tickets
where id_client in (_a_list_of_client_id)
There are a couple other ways to do this (using if for example or leaving out the case), but I think this is easy to read. I believe mysql will work with sum(status='new') for example.