SQL query to group transactions by month - mysql

----------------------------------------
|transaction_id|customer_id|month|value|
----------------------------------------
I am looking for a SQL query that would return customers ID of the customers that had more transactions in the month of October instead of November or of customers that ONLY had transactions in November (and none in October). The month column is of type string (not a date)
I was thinking an inner join could do it, but past that I do not know how to approach this problem.
This is what I attempted
select customer_id
from tbl_name
where (select count(month is 'October') > count(month is 'November') from tbl_name)
Thank you

You count records. So you aggregate. You want counts per customer_id. So you'd group by customer_id. You forgot this in your query.
Then you'd compare the counts in the HAVING clause, i.e. after having counted October and November records.
select customer_id
from tbl_name
where month in ('October', 'November')
group by customer_id
having count(case when month = 'October' then 1 end) >
count(case when month = 'November' then 1 end)
or count(case when month = 'October' then 1 end) = 0;
You don't need to access the table twice as you see. Just aggregate and see what you have :-)

Related

Getting the number of users for this year and last year in SQL

My table is like this:
root_tstamp
userId
2022-01-26T00:13:24.725+00:00
d2212
2022-01-26T00:13:24.669+00:00
ad323
2022-01-26T00:13:24.629+00:00
adfae
2022-01-26T00:13:24.573+00:00
adfa3
2022-01-26T00:13:24.552+00:00
adfef
...
...
2021-01-26T00:12:24.725+00:00
d2212
2021-01-26T00:15:24.669+00:00
daddfe
2021-01-26T00:14:24.629+00:00
adfda
2021-01-26T00:12:24.573+00:00
466eff
2021-01-26T00:12:24.552+00:00
adfafe
I want to get the number of users in the current year and in previous year like below using SQL.
Date Users previous_year
2022-01-01 10 5
2022-01-02 20 15
The code is written as follows.
select CAST(root_tstamp as DATE) as Date,
count(DISTINCT userid) as users,
count(Distinct case when CAST(root_tstamp as DATE) = dateadd(MONTH,-12,CAST(root_tstamp as DATE)) then userid end) as previous_year
FROM table1
But it returns 0 for previous_year values.
How can I fix that?
Possible solution for SQL Server:
WITH cte AS ( SELECT 2022 [year]
UNION ALL
SELECT 2021 )
SELECT cte.[year],
COUNT(DISTINCT test.userId) current_users_amount,
COUNT(DISTINCT CASE WHEN YEAR(test.root_tstamp) < cte.[year]
THEN test.userId
END) previous_users_amount
FROM test
JOIN cte ON YEAR(test.root_tstamp) <= cte.[year]
GROUP BY cte.[year]
https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=88b78aad9acd965bdbac4c85a0b81927
This query (for MySql) returns unique number of userids where the root_timestamp is in the current year, by day, and the number of unique userids for the same day last year. If there is no record for a day in the current year nothing will be displayed for that day. If there are rows for the current year, but no rows for the same day last year, then NULL will be shown for that lastyear column.
SELECT cast(ty.root_tstamp as date) as Dte,
COUNT(DISTINCT ty.userId) as users_this_day,
count(distinct lysd.userid) as users_sameday_lastyear
FROM test ty
left join
test lysd
on cast(lysd.root_tstamp as date)=date_add(cast(ty.root_tstamp as date), interval -1 year)
WHERE YEAR(ty.root_tstamp) = year(current_date())
GROUP BY Dte
If you wish to show output rows for calendar days even if there are no rows in current year and/or last year, then you also need a calendar table to be introduced (let's hope that it is not what you need)

SQL reporting active users and logins

I have a SQL Table of logins as a data source, and each row has an id, timestamp and user_id.
Similar to this:
id
timestamp
user_id
1
2022-01-01T15:17:13.000Z
234
2
2022-01-02T15:17:13.000Z
235
I want to build a report that shows an aggregate of logins by year. So something like (for all months, just using January as an example.):
Year
Active Users in January
Logins in January
2019
500
10000
2020
600
10002
Essentially, the active users would be grouping the rows of logins by user_id, and the logins would just aggregate the timestamps by month.
Is this kind of view something I build using a SQL query?
You may use aggregation here:
SELECT
YEAR(timestamp) AS Year,
COUNT(DISTINCT user_id) AS `Active Users in January`,
COUNT(*) AS `Logins in January`
FROM yourTable
WHERE
MONTH(timestamp) = 1
GROUP BY
YEAR(timestamp);
The number of active users is given by the distinct count of users for a given year, in the month of January. The number of logins is just the number of entries for a given year in January.
If you want to report for all months and all years, then use:
SELECT
DATE_FORMAT(timestamp, '%Y-%m') AS ym,
COUNT(DISTINCT user_id) AS `Active Users per month`,
COUNT(*) AS `Logins in month`
FROM yourTable
GROUP BY 1;

How to handle where Date if no records for date

I'm setting up a graph that display number of new contracts per employee per month. Not every month as records in my table, how do display 0 as contracts count for every employee on month that have no records?
SELECT EmployeeName, SUM(contract) as nbcontract
FROM table
WHERE month(Date) = month(now())
group by EmployeeName
Current result when no records for month(now):
EmployeeName|nbcontract
Expected result:
EmployeeName|nbcontract
employee1 0
employee2 0
employee3 0
...
Where EmployeeName displays all possible distinct value of EmployeeName
Any hint would be appreciated!
Use conditional aggregation:
SELECT
EmployeeName,
SUM(CASE WHEN MONTH(date) = MONTH(NOW()) THEN contract ELSE 0 END) AS nbcontract
FROM yourTable
GROUP BY
EmployeeName;
This approach would guarantee that every employee would appear in the result set, even if he has no contracts in the current month.

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.

Selecting from the same table twice with results on the same line

I want to generate a monthly report of total payments received from clients and total sent to suppliers in a single mySQL query that return these two totals on the same line. I can do it with UNION but that returns the results on different rows. All payments are in a payments table with the basic structure:
id | id_order | id_contact | amount | date_time
Update:
contact_id can be either client or supplier. The related contacts table has a field contact_typewhich is either "SUP" or "CLI".
I would like the result to sum up all the payments received from clients and sent to suppliers during a time frame so I can generate the profit based on actual payments not the theoretical profit based on order sale price - my cost, especially because these orders are paid in installments over a long period of time so showing $5000 profit in June for an order placed in June is not relevant as long as the order is being paid 3000 in August and another 2000 in December.
Month | total $ sent to suppliers | total $ received from clients
June 2014 3000 5000
July 2014 2500 3800
Other supporting tables that I have are the "orders" table, the "contacts" table. Is there a way to do this with joins? Is this possible and OK performance wise and if not what other options do I have? (I am using MySQL 5.5 and will do this in PHP, if it matters)
You would use conditional aggregation. You don't provide key information, such as how you know whether someone is a supplier or client. The following is a sketch of what the query would look like:
select date_format(date_time, '%M %Y') as month,
sum(case when contact_id = "supplier" then amount else 0 end) as sent,
sum(case when contact_id = "client" then amount else 0 end) as received
from table t
group by date_format(date_time, '%M %Y')
order by min(date_time);
Note the order by. Because you are using a non-standard date format, this will still ensure that the rows are in temporal order.
This is the solution I came up with, based on #Gordon Linoff answer
select date_format(p.pay_dcreated, '%M %Y') as month,
sum(case when c.type_con = "FAC" then p.pay_amount else 0 end) as sent,
sum(case when c.type_con = "CST" then p.pay_amount else 0 end) as received
from payments_pay as p, contacts_con as c
where p.pay_idcon=c.id_con
group by date_format(p.pay_dcreated, '%M %Y')
order by min(p.pay_dcreated);
This gives me a result I wanted.