Yearly income and expenses table - mysql

i have two tables
Income
(id,
income,
date,
userid)
and table
Expense
(id,amount,date,userid). Now I'm trying to create a View with sum of income, sum of amount in one year. Also it must be GROUPED by year and userid.
So new table (view) must have sum of income, expenses, year. Right now i am stuck on this code.
SELECT
id,
i.Prihod,
e.Rashod,
YEAR
YEAR(COALESCE(e.god, i.godi))) AS Godina ,
users_id
FROM
(
SELECT
sum(insum) as 'Prihod',
YEAR(datum) as 'Godi',
users_id
FROM
GROUP BY users_id
) as i
FULL OUTER JOIN
(
SELECT
sum(amount) as 'Rashod',
YEAR(datum) as 'God',
users_id
FROM expense
GROUP BY users_id
) as e

This is a job for the structured part of structured query language. Start with three subqueries (virtual tables).
First: A list of the years and users. You need this because MySQL doesn't have FULL OUTER JOIN capability. If you write this query correctly, it will contain one row for each user for each year you need.
SELECT DISTINCT YEAR(datum) Godi, users_id FROM income
UNION
SELECT DISTINCT YEAR(datum) Godi, users_id FROM expense
Second, a summary of the income by year and user.
SELECT sum(insum) as Prihod,
YEAR(datum) as Godi,
users_id
FROM income
GROUP BY YEAR(datum), users_id
Third, a similar sum of expenses by year and user
SELECT sum(amount) as Rashod,
YEAR(datum) as God,
users_id
FROM expense
GROUP BY YEAR(datum), users_id
Next, test these subqueries individually, standalone, to ensure you have the results you expect.
Finally, join them together as if they were tables, like so
SELECT yr.users_id, yr.Godi, inc.Prihod, exp.Rashod
FROM (
SELECT DISTINCT YEAR(datum) Godi, users_id FROM income
UNION
SELECT DISTINCT YEAR(datum) Godi, users_id FROM expense
) yr
LEFT JOIN (
SELECT sum(insum) as Prihod,
YEAR(datum) as Godi,
users_id
FROM income
GROUP BY YEAR(datum), users_id
) inc ON yr.users_id = inc.users_id AND yr.Godi = inc.Godi
LEFT JOIN (
SELECT sum(amount) as Rashod,
YEAR(datum) as God,
users_id
FROM expense
GROUP BY YEAR(datum), users_id
) exp ON yr.users_id = exp.users_id AND yr.Godi = exp.God
The query pattern here is to develop three subqueries. The first of them determines the number of rows in your final result set, because it contains one row for each desired row. The second and third queries have one, or maybe zero, rows for each row you need in your final result set. Then you join them together.

Related

SQL Consecutive Monthly Purchases

I'm having great difficulty writing this query and cannot find any answers online which could be applied to my problem.
I have a couple of tables which looks similar to the below with. Each purchase date corresponds with an item purchased.
Cust_ID
Purchase_Date
123
08/01/2022
123
08/20/2022
123
09/05/2022
123
10/08/2022
123
12/25/2022
123
01/26/2023
The result I am looking for should contain the customers ID, a range of the purchases, the number of consecutive months they had made a purchase (regardless of which day they purchased), and a count of how many purchases they had made in the time frame. The result should look something like the below for my example.
Cust_ID
Min Purchase Date
Max Purchase Date
Consecutive Months
No. Items Purchased
123
08/01/2022
10/08/2022
3
4
123
12/25/2022
01/26/2023
2
2
I have tried using CTEs with querys similar to
WITH CTE as
(
SELECT
PaymentDate PD,
CustomerID CustID,
DATEADD(m, -ROW_NUMBER() OVER (PARTITION BY c.CustomerID ORDER BY
DATEPART(m,PaymentDate)), PaymentDate) as TempCol1,
FROM customers as c
LEFT JOIN payments as p on c.customerid = p.customerid
GROUP BY c.CustomerID, p.PaymentDate
)
SELECT
CustID,
MIN(PD) AS MinPaymentDate,
MAX(PD) AS MaxPaymentDate,
COUNT(*) as ConsecutiveMonths,
FROM CTE
GROUP BY CustID, TempCol1
However, the above failed to properly count consecutive months. When the payment dates matched a month apart (e.g. 1/1/22 - 2/1/22), the query properly counts the consecutive months. However, if the dates do not match from month to month (e.g. 1/5/22 - 2/15/22), the count breaks.
Any guidance/help would be much appreciated!
This is just a small enhancement on the answer already given by ahmed. If your date range for this query is more than a year, then year(M.Purchase_Date) + month(M.Purchase_Date) will be 2024 for both 2022-02-01 and 2023-01-01 as YEAR() and MONTH() both return integer values. This will return incorrect count of consecutive months. You can change this to use CONCAT() or FORMAT(). Also, the COUNT(*) for ItemsPurchased should be counting the right hand side of the join, as it is a LEFT JOIN.
WITH consecutive_months AS
(
SELECT *,
DATEADD(
month,
-DENSE_RANK() OVER (
PARTITION BY CustomerID
ORDER BY YEAR(PaymentDate), MONTH(PaymentDate)
),
PaymentDate
) AS grp_date
FROM payments
)
SELECT
C.CustomerID AS CustID,
MIN(M.PaymentDate) AS MinPaymentDate,
MAX(M.PaymentDate) AS MaxPaymentDate,
COUNT(DISTINCT FORMAT(M.PaymentDate, 'yyyyMM')) AS ConsecutiveMonths,
COUNT(M.CustomerID) AS ItemsPurchased
FROM customers C
LEFT JOIN consecutive_months M
ON C.CustomerID = M.CustomerID
GROUP BY C.CustomerID, YEAR(M.grp_date), MONTH(M.grp_date)
Here's a db<>fiddle
You need to use the dense_rank function instead of the row_number, this will give the same rank for the same months and avoid breaking the grouping column. Also, you need to aggregate for 'year-month' of the grouping date column.
with consecutive_months as
(
select *,
Purchase_Date - interval
dense_rank() over (partition by Cust_ID order by year(Purchase_Date), month(Purchase_Date))
month as grp_date
from payments
)
select C.Cust_ID,
min(M.Purchase_Date) as MinPurchaseDate,
max(M.Purchase_Date) as MaxPurchaseDate,
count(distinct year(M.Purchase_Date), month(M.Purchase_Date)) as ConsecutiveMonthsNo,
count(M.Cust_ID) as ItemsPurchased
from customers C left join consecutive_months M
on C.Cust_ID = M.Cust_ID
group by C.Cust_ID, year(M.grp_date), month(M.grp_date)
See demo on MySQL
You tagged your question with MySQL, while it seems that you posted an SQL Server query syntax, for SQL Server just use dateadd(month, -dense_rank() over (partition by Cust_ID order by year(Purchase_Date), month(Purchase_Date)), Purchase_Date).
See demo on SQL Server.

how can i make query with couple of profits?

first ,i need to get the sum of TotalPrice of sport's and music's departments from the first 3 months of 2016,second, i need to get the result of what i wrote before dividing to sum of all TotalPrice at the year of 2016 from all departments, and third- i need to get the first result dividing to sum of all Total price from all over the years.
all this at the same query!
thanks!
the table called Sales and the attributes are: S_id, date, department, totalPrice.
THIS IS MY CHRY :
Select sum(TotalPrice) as sportMusic, sportMusic/sum(TotalPrice)
From Sales
Where (Department="MUSIC" OR Department="SPORT") and
DATE BETWEEN "2016/01/01" AND "2016/03/31"
You can use your query and two more queries as subqueries (also called "derived tables") in your from clause. Cross join the three result rows and use the totals in your select clause. Something along the lines of:
select
ms_2016_q1.total as ms_2016_q1_total,
ms_2016_q1.total / all_2016.total as rate_2016,
ms_2016_q1.total / all_years.total as rate_all
from
(
select sum(totalprice) as total
from sales
where department in ('MUSIC', 'SPORT')
and date between date '2016-01-01' and date '2016-03-31'
) ms_2016_q1
cross join
(
select sum(totalprice) as total
from sales
where date between date '2016-01-01' and date '2016-12-31'
) all_2016
cross join
(
select sum(totalprice) as total
from sales
) all_years;

Get data from between two dates

I have these two tables
The first one is expenses table and the second one is expensename
Exp_Type(first table) is the Expense name(second table) as 2 is Food
I am trying to group expense according to expense type and get data between certain dates.
This is what i have tried, but it wont work.
select
(select
(select name from EXPENSENAME where id=EXP_TYPE)as ExpenseType,
sum(PRICE) as cost
from EXPENSES WHERE USERID=1 GROUP BY EXPENSES.EXP_TYPE),
[date]
from EXPENSES where [date] BETWEEN '10-09-2015' and '10-18-2015 23:59:59'
And
select
(select name from EXPENSENAME where id=EXP_TYPE)as ExpenseType,
sum(PRICE) as cost,
date
from EXPENSES WHERE USERID=1 and DATE BETWEEN '01/10/2015' and '29/10/2015' GROUP BY EXPENSES.EXP_TYPE
With out date, i am getting result by this query but i need the same data between certain dates,please help
select
(select name from EXPENSENAME where id=EXP_TYPE)as ExpenseType,
sum(PRICE) as cost
from EXPENSES WHERE USERID=1 GROUP BY EXPENSES.EXP_TYPE
you want to join the tables together
SELECT en.name as ExpenseType, SUM(e.price) as cost
FROM expenses e
JOIN expensename en ON en.id = e.exp_type
WHERE e.date BETWEEN '10-09-2015' and '10-18-2015'
GROUP BY en.name
this should give you the cost per name
the current query you have is TERRIBLE... and this is why
SELECT (SELECT ... FROM ... WHERE ... ) as ...
this is creating a correlated subquery which is executing once for every row of the parent select. meaning if you have a table with 4 rows in it (SELECT ... FROM ... WHERE ... ) will execute 4 times scanning 16 rows (assuming its from the same table) in general that is a really really bad way to get data... if you have a million rows... well do the math, its a bad idea

Real world total sales SQL query

I'm fairly new to SQL and am having difficulty solving a problem.
'What are the total sales across all products for the salespeople that sell at least one unit of each of the five individual products with the highest sales by unit? Make sure that the query returns the total sales dollars in descending order. Only consider sales that take place over the six complete months prior to a #target_date parameter.'
3 tables exist in the DB.
SalesPerson (SalesPersonID,SalesYTD)
SalesOrderHeader (SalesOrderID,OrderDate,ShipDate)
SalesOrderDetail (SalesOrderID,SalesOrderDetailID,OrderQty,ProductID,UnitPrice)
This is where I'm at so far. I need to compile what I have into one statement and make necessary revisions. Please help!
To capture the top 5 highest sales by unit, the following SYNTAX should work:
SELECT
ProductID,
SUM(Orderqty*Unitprice)
FROM SalesOrderDetail
GROUP BY ProductID
WHERE Orderqty >=1
AND COUNT(productID) =5
ORDER BY SUM(Orderqty*Unitprice) DESC
LIMIT 5;
For the target_date parameter, I think it would be something along these lines?
SELECT
SalespersonID AS ‘Sales Representative’,
SalesYTD AS ‘Total Sales’, target_date
FROM Salesperson
WHERE target_date BETWEEN ‘01-DEC-13’ AND ’01-May-14’;
For the top five highest sales, I would rather propose the slightly simplified
select productid, sum(orderqty * unitprice) as sales
from salesorderdetail
group by productid
order by sales desc
limit 5
and for the six months prior to #target_date something like
where orderdate between date_sub(#target_date, interval 6 months) and #target_date
Assuming a FK SalesOrderDetail(SalesPersonID), you can then join the tables and top five sales as
select p.*
from salesperson p
join salesorderheader h on h.salespersionid = p.salespersionid
join salesorderdetail d on d.salesorderid = h.salesorderid
join (select productid, sum(orderqty * unitprice) as sales
from salesorderdetail
group by productid
order by sales desc
limit 5) t5 on t5.productid = d.productid
where h.orderdate between date_sub(#target_date, interval 6 months) and #target_date
order by p.salesytd desc

How to use group concat with group by?

Here my table is having filed as following:
employee_id,
expense_id,
expense_type,
expense_cost,
expense_date and etc,
And i want to display as month wise expenses as row wise for particular employee.
in my table data has stored like
2wheeler 01/03/2014 99 Santhosh 4493.00 March 500.00
Auto 03/02/2014 99 Santhosh 0.00 February 80.00
Food 01/02/2014 99 Santhosh 0.00 February 200.00
Phone Expense 01/03/2014 99 Santhosh 0.00 March 500.00
In this table i want to get out as
single user row with concat of expense type and sum of cost for every month that mean : march have single row with concat of expense type & sum of cost.
I would suggest doing a sub query that sums up all the occurances of an expenses per employee per month per expense. Then use that as a source to get the list of employees, months and the GROUP_CONCATed list of expense types and the total cost of them.
Like this:-
SELECT employee_id, expense_month, GROUP_CONCAT(CONCAT_WS('=', expense_type, monthly_exployee_expense))
FROM
(
SELECT employee_id, MONTH(expense_date) AS expense_month, expense_type, SUM(expense_cost) AS monthly_exployee_expense
FROM some_table
GROUP BY employee_id, expense_month, expense_type
) Sub1
GROUP BY employee_id, expense_month
EDIT
Reading you comment it seems that you need an expense listed even when an employee has not incurred that expense that month.
To do that I think you will need to cross join the employees (I have assumed a table name of tbl_employee) with the table of expenses types, and also all the possible months (assuming you want a row for a month for an employee when that employee has had no expenses that month). I have got the possible months by just selecting the distinct year / month from the table listing all the expenses (but there are other ways to get this - depends if there are any months where no employees had any expenses and if you want to put these out anyway).
Once those are cross joined to get every combination of employee, month and expense you can left join the actual expenses in the sub query, and then do the GROUP_CONCAT much as before.
Not tested, but something like this:-
SELECT employee_id, expense_month, GROUP_CONCAT(CONCAT_WS('=', exp_type_text, monthly_exployee_expense))
FROM
(
SELECT tbl_employee.employee_id, expense_months.expense_month, tbl_expense_type.exp_type_id, tbl_expense_type.exp_type_text, SUM(expense_cost) AS monthly_exployee_expense
FROM tbl_employee
CROSS JOIN tbl_expense_type
CROSS JOIN
(
SELECT DISTINCT DATE_FORMAT(expense_date, '%Y%m') AS expense_month
FROM some_table
) expense_months
LEFT OUTER JOIN some_table
ON tbl_employee.employee_id = some_table.employee_id
AND tbl_expense_type.exp_type_id = some_table.expense_type
AND expense_months.expense_month = DATE_FORMAT(some_table.expense_date, '%Y%m')
GROUP BY tbl_employee.employee_id, expense_months.expense_month, tbl_expense_type.exp_type_id, tbl_expense_type.exp_type_text
) Sub1
GROUP BY employee_id, expense_month