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

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.

Related

How to write an sql query that calculate sales monthly for a particular year?

I have a database that contain a record from 2017-2021. But I need an sql code to calculate sales monthly for just 2017 alone.
It's a two different table I'm trying to call in the coding
SELECT sum(itemPrice) From article,
Month(TransactionDate) FROM transactionid WHERE
year(TransactionDate) = 2017 group by 1
If I understand your query properly, it looks like you have 2 tables called article and transactionid. I assume these 2 tables have a relationship together which I called article_id in the example below.
This would be pretty close to what you need, you just need set the correct column names:
SELECT MONTH(TransactionDate) as month, SUM(itemPrice) as total_sales
FROM article
JOIN transactionid ON transactionid.article_id = article.id
WHERE YEAR(TransactionDate) = 2017
GROUP BY MONTH(TransactionDate)
ORDER BY month;

Is there a way to return non existent values when using groupby and union all?

I have a table that I'm trying to return summarized results from for a chart that will have two datasets, one for debit transactions that have happened each month and one for payments that have happened each month. The table I'm querying looks like this:
ID amount type created_date
1 200 Debit 2020-02-14
2 150 Payment 2020-02-15
3 200 Payment 2020-02-21
4 100 Debit 2020-03-01
5 100 Debit 2020-03-05
6 50 Payment 2020-04-01
7 150 Payment 2020-04-02
What I'm looking to get back out of my query is a result that does a sum(amount) once for each type and unions them together so that the result looks something like this:
month debit_sum payment_sum
February 200 350
March 200 0
April 0 200
So far I've gotten to the below query which returns mostly the right data but in the wrong format.
SELECT MONTHNAME(created_date) as month_name, type as type_name, sum(amount) as amount
FROM
(
SELECT created_date, amount, type
FROM balance_adjustments
WHERE type = 'Payment'
AND created_date > '2020-01-01'
GROUP BY MONTHNAME(created_date)
UNION ALL
SELECT created_date, amount, type
FROM balance_adjustments
WHERE type = 'Debit'
AND created_date > '2020-01-01'
GROUP BY MONTHNAME(created_date)
) AS adjustments
GROUP BY type, MONTHNAME(created_date)
ORDER BY created_date;
This returns the below, which you can see returns one row for each type, but doesn't return a row if there is no values to sum. I could work with this format if I could have it return 2 rows for each month (one for each type) and if there is no values return 0.
month type_name amount
February Debit 200
February Payment 350
March Debit 200
April Payment 200
What I can't figure out is if there is a way to either return the above with non-existent values getting filled in with 0 or if there is a way to do sum(amount) twice, once for each type as separate columns.
If I follow you correctly, you can use conditional aggregation:
select extract(year_month from created_date) created_month,
sum(case when type = 'Debit' then amount else 0 end) as debit_sum,
sum(case when type = 'Payment' then amount else 0 end) as payment_sum
from balance_adjustments
where created_at >= '2020-01-01'
group by created_month
I used year_month instead of the name of the month, since you probably want to not count the same month in different years together. You can change that to something else if you want otherwise.

I would like to count the number of users who made multiple purchases grouped by month

So what i'm trying to do here, is that i am trying to count the number of repeat users (users who made more than one order) in a period of time, let it be month day or year, the case here is months
i'm currently running mysql mariadb and i'm pretty much a beginner in mysql, i've tried multiple subqueries but all have failed till now
This is what i have tried so far ..
This returns all the number of users with no ordering count condition
Since people are asking for sample data, here is what the data is looking like at the moment:
Order_Creation_Date - User_ID - Order_ID
2019-01-01 123 1
2019-01-01 123 2
2019-01-01 231 3
2019-01-01 231 4
This is the query i am using to get the result but it keeps on returning total number of users within the month
select month(o.created_at)month,
year(o.created_at)year,
count(distinct o.user_uuid) from orders o
group by month(o.created_at)
having count(*)>1
and this returns the number of users as 1 ..
select month(o.created_at)month,
year(o.created_at)year,
(select count(distinct ord.user_uuid) from orders ord
where ord.user_uuid = o.user_uuid
group by ord.user_uuid
having count(*)>1) from orders o
group by month(o.created_at)
Expected result will be from the sample data above
Month Count of repeat users
1 2
If you want the number of users that make more than one purchase in January, then do two levels of aggregations: one by user and month and the other by month:
select yyyy, mm, sum( num_orders > 1) as num_repeat_users
from (select year(o.created) as yyyy, month(o.created) as mm,
o.user_uuid, count(*) as num_orders
from orders o
group by yyyy, mm, o.user_uuid
) o
group by yyyy, mm;
I think you should try something like this which will return USer_ID list Month and Year wise who ordered more that once for the period-
SELECT
[user_uuid],
MONTH(o.created_at) month,
YEAR(o.created_at) year,
COUNT(o.user_uuid)
FROM orders o
GROUP BY
MONTH(o.created_at),YEAR(o.created_at)
HAVING COUNT(*) > 1;
For more, if you are looking for the count that how many users placed more that one order, you can just place the above query as a sub query and make a count on column 'user_uuid'

Calculate new users subscription amount MySQL

I have a dataset where I need to find out New subscribers revenue.
These are subscribers that are paying either weekly or monthly depending on the subscription they are on.
The unique identifier is "customer" and the data is at timestamp level, but I want it rolled up at monthly level.
Now for each month, we need to find out revenue for only NEW subscribers.
Basically, imagine customers being on monthly/weekly subscriptions and we only want their FIRST Payments to be counted here.
Here's a sample dataset and
created customer amount
16-Feb-18 14:03:55 cus_BwcisIF1YR1UlD 33300
16-Feb-18 14:28:13 cus_BpLsCvjuubYZAe 156250
15-Feb-18 19:19:14 cus_C3vT6uVBqJC1wz 50000
14-Feb-18 23:00:24 cus_BME5vNeXAeZSN2 162375
9-Feb-18 14:27:26 cus_BpLsCvjuubYZAe 156250
....and so on...
here is the final desired output
yearmonth new_amount
Jan - 2018 100000
Feb - 2018 2000
Dec - 2017 100002
This needs to be done in MySQL interface.
Basically, you want to filter the data to the first customer. One method of doing this involves a correlated subquery.
The rest is just aggregating by year and month. So, overall the query is not that complicated, but it does consist of two distinct parts:
select year(created) as yyyy, month(created) as mm,
count(*) as num_news,
sum(amount) as amount_news
from t
where t.created = (select min(t2.created)
from t t2
where t2.customer = t.customer
)
group by yyyy, mm
We can have sql subquery for only the 1st payment of the new customer with
amount for every month and year
The query is as follows
SELECT month(created) as mm,year(created) as yyyy,
sum(amount) as new_amount
FROM t
WHERE t.created=(select min(t2.created) from t t2 where
t2.customer=t.customer)

SQL query to group transactions by month

----------------------------------------
|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 :-)