Join issue on SQL request - sql

My database :
TB_DW_VAB_FLIGHT : ID_TEC_FLIGHT
TB_DW_VAB_SALES : QUANTITY, TRANSACTION_NUMBER, UNIT_SALES_PRICE
I want to have a table with 4 columns as result : CA, QTE, NB_TRANSACTION and NB_VOLS at the same month. ( N-1 )
I tried a SQL request like this :
SELECT
sum(QUANTITY*UNIT_SALES_PRICE) as CA,
sum(QUANTITY) as QTE,
count(distinct TRANSACTION_NUMBER) as NB_TRANSACTION,
count(distinct ID_TEC_FLIGHT) as NB_VOLS
FROM TB_DW_VAB_SALES, TB_DW_VAB_FLIGHT
where to_char(TB_DW_VAB_SALES.FLIGHT_DATE,'MM')=to_char(current_date,'MM')-1 and to_char(TB_DW_VAB_SALES.FLIGHT_DATE,'YYYY')=to_char(current_date,'YYYY') and SALES_TYPE='SALES'
and to_char(TB_DW_VAB_FLIGHT.FLIGHT_DATE,'MM')=to_char(current_date,'MM')-1 and to_char(TB_DW_VAB_FLIGHT.FLIGHT_DATE,'YYYY')=to_char(current_date,'YYYY');
But Oracle can't give me an answer.
Thank you a lot for any help.

Try
with CTE1 as
(
select to_char(FLIGHT_DATE, 'MM-YYYY') as PERIOD,
sum(QUANTITY*UNIT_SALES_PRICE) as CA,
sum(QUANTITY) as QTE,
count(distinct TRANSACTION_NUMBER) as NB_TRANSACTION
from TB_DW_VAB_SALES
where SALES_TYPE = 'SALES'
group by to_char(FLIGHT_DATE, 'MM-YYYY')
)
, CTE2 as
(
select count(distinct ID_TEC_FLIGHT) as NB_VOLS,
to_char(FLIGHT_DATE, 'MM-YYYY') as PERIOD
from TB_DW_VAB_FLIGHT
group by to_char(FLIGHT_DATE, 'MM-YYYY')
)
select CTE1.CA,
CTE1.QTE,
CTE1.NB_TRANSACTION,
CTE2.NB_VOLS
from CTE1
inner join CTE2 on CTE1.PERIOD = CTE2.PERIOD
where CTE1.PERIOD = to_char(add_Months(sysdate,-1),'MM-YYYY')
or if CTE's are not available in your software:
select CTE1.CA,
CTE1.QTE,
CTE1.NB_TRANSACTION,
CTE2.NB_VOLS
from
(
select to_char(FLIGHT_DATE, 'MM-YYYY') as PERIOD,
sum(QUANTITY*UNIT_SALES_PRICE) as CA,
sum(QUANTITY) as QTE,
count(distinct TRANSACTION_NUMBER) as NB_TRANSACTION
from TB_DW_VAB_SALES
where SALES_TYPE = 'SALES'
group by to_char(FLIGHT_DATE, 'MM-YYYY')
) CTE1
inner join
(
select count(distinct ID_TEC_FLIGHT) as NB_VOLS,
to_char(FLIGHT_DATE, 'MM-YYYY') as PERIOD
from TB_DW_VAB_FLIGHT
group by to_char(FLIGHT_DATE, 'MM-YYYY')
) CTE2
on CTE1.PERIOD = CTE2.PERIOD
where CTE1.PERIOD = to_char(add_Months(sysdate,-1),'MM-YYYY')

Related

Add running or cumulative total

I have below query which gives me expected results:
SELECT
total_orders,
quantity,
available_store_credits
FROM
(
SELECT
COUNT(orders.id) as total_orders,
date_trunc('year', confirmed_at) as year,
date_trunc('month', confirmed_at) as month,
SUM( quantity ) as quantity,
FROM
orders
INNER JOIN (
SELECT
orders.id,
sum(quantity) as quantity
FROM
orders
INNER JOIN line_items ON line_items.order_id = orders.id
WHERE
orders.deleted_at IS NULL
AND orders.status IN (
'paid', 'packed', 'in_transit', 'delivered'
)
GROUP BY
orders.id
) as order_quantity
ON order_quantity.id = orders.id
GROUP BY month, year) as orders_transactions
FULL OUTER JOIN
(
SELECT
date_trunc('year', created_at) as year,
date_trunc('month', created_at) as month,
SUM( ROUND( ( CASE WHEN amount_in_cents > 0 THEN amount_in_cents end) / 100, 2 )) AS store_credit_given,
SUM( ROUND( amount_in_cents / 100, 2 )) AS available_store_credits
FROM
store_credit_transactions
GROUP BY month, year
) as store_credit_results
ON orders_transactions.month = store_credit_results.month
I want to add one more column beside available_store_credits which will calculate running total of available_store_credits.
These are my trials, but none are working:
Attempt #1
SELECT
total_orders,
quantity,
available_store_credits,
cum_amt
FROM
(
SELECT
COUNT(orders.id) as total_orders,
date_trunc('year', confirmed_at) as year,
date_trunc('month', confirmed_at) as month,
SUM( quantity ) as quantity,
FROM
orders
INNER JOIN (
SELECT
orders.id,
sum(quantity) as quantity
FROM
orders
INNER JOIN line_items ON line_items.order_id = orders.id
WHERE
orders.deleted_at IS NULL
AND orders.status IN (
'paid', 'packed', 'in_transit', 'delivered'
)
GROUP BY
orders.id
) as order_quantity
ON order_quantity.id = orders.id
GROUP BY month, year) as orders_transactions
FULL OUTER JOIN
(
SELECT
date_trunc('year', created_at) as year,
date_trunc('month', created_at) as month,
SUM( ROUND( ( CASE WHEN amount_in_cents > 0 THEN amount_in_cents end) / 100, 2 )) AS store_credit_given,
SUM( ROUND( amount_in_cents / 100, 2 )) AS available_store_credits
SUM( amount_in_cents ) OVER (ORDER BY date_trunc('month', created_at), date_trunc('year', created_at)) AS cum_amt
FROM
store_credit_transactions
GROUP BY month, year
) as store_credit_results
ON orders_transactions.month = store_credit_results.month
Attempt #2
SELECT
total_orders,
quantity,
available_store_credits,
running_tot
FROM
(
SELECT
COUNT(orders.id) as total_orders,
date_trunc('year', confirmed_at) as year,
date_trunc('month', confirmed_at) as month,
FROM
orders
INNER JOIN (
SELECT
orders.id,
sum(quantity) as quantity
FROM
orders
INNER JOIN line_items ON line_items.order_id = orders.id
WHERE
orders.deleted_at IS NULL
AND orders.status IN (
'paid', 'packed', 'in_transit', 'delivered'
)
GROUP BY
orders.id
) as order_quantity
ON order_quantity.id = orders.id
GROUP BY month, year) as orders_transactions
FULL OUTER JOIN
(
SELECT
date_trunc('year', created_at) as year,
date_trunc('month', created_at) as month,
SUM( ROUND( amount_in_cents / 100, 2 )) AS available_store_credits,
SUM (available_store_creds) as running_tot
FROM
store_credit_transactions
INNER JOIN (
SELECT t0.id,
(
SELECT SUM( ROUND( amount_in_cents / 100, 2 )) as running_total
FROM store_credit_transactions as t1
WHERE date_trunc('month', t1.created_at) <= date_trunc('month', t0.created_at)
) AS available_store_creds
FROM store_credit_transactions AS t0
) as results
ON results.id = store_credit_transactions.id
GROUP BY month, year
) as store_credit_results
ON orders_transactions.month = store_credit_results.month
Making some assumptions about the undisclosed table definition and Postgres version (assuming current Postgres 14), this should do it:
SELECT total_orders, quantity, available_store_credits
, sum(available_store_credits) OVER (ORDER BY month) AS cum_amt -- HERE!!
FROM (
SELECT date_trunc('month', confirmed_at) AS month
, count(*) AS total_orders
, sum(quantity) AS quantity
FROM (
SELECT o.id, o.confirmed_at, sum(quantity) AS quantity
FROM orders o
JOIN line_items l ON l.order_id = o.id
WHERE o.deleted_at IS NULL
AND o.status IN ('paid', 'packed', 'in_transit', 'delivered')
GROUP BY 1
) o
GROUP BY 1
) orders_transactions
FULL JOIN (
SELECT date_trunc('month', created_at) AS month
, round(sum(amount_in_cents) FILTER (WHERE amount_in_cents > 0) / 100, 2) AS store_credit_given
, round(sum(amount_in_cents) / 100, 2) AS available_store_credits
FROM store_credit_transactions
GROUP BY 1
) store_credit_results USING (month)
Assuming you want the running sum to show up in every row and order of the date.
First, I simplified and removed some cruft:
date_trunc('year', confirmed_at) as year, was 100 % redundant noise in your query. I removed it.
As was another join to orders. Removed that, too. Assuming orders.id is defined as PK, we can further simplify. See:
PostgreSQL - GROUP BY clause
Use the superior aggregate FILTER. See:
Aggregate columns with additional (distinct) filters
Simplified a couple of other minor bits.

conditional running sum

I'm trying to return the number of unique users that converted over time.
So I have the following query:
WITH CTE
As
(
SELECT '2020-04-01' as date,'userA' as user,1 as goals Union all
SELECT '2020-04-01','userB',0 Union all
SELECT '2020-04-01','userC',0 Union all
SELECT '2020-04-03','userA',1 Union all
SELECT '2020-04-05','userC',1 Union all
SELECT '2020-04-06','userC',0 Union all
SELECT '2020-04-06','userB',0
)
select
date,
COUNT(DISTINCT
IF
(goals >= 1,
user,
NULL)) AS cad_converters
from CTE
group by date
I'm trying to count distinct user but I need to find a way to apply the distinct count to the whole date. I probably need to do something like a cumulative some...
expected result would be something like this
date, goals, total_unique_converted_users
'2020-04-01',1,1
'2020-04-01',0,1
'2020-04-01',0,1
'2020-04-03',1,2
'2020-04-05',1,2
'2020-04-06',0,2
'2020-04-06',0,2
Below is for BigQuery Standard SQL
#standardSQL
SELECT t.date, t.goals, total_unique_converted_users
FROM `project.dataset.table` t
LEFT JOIN (
SELECT a.date,
COUNT(DISTINCT IF(b.goals >= 1, b.user, NULL)) AS total_unique_converted_users
FROM `project.dataset.table` a
CROSS JOIN `project.dataset.table` b
WHERE a.date >= b.date
GROUP BY a.date
)
USING(date)
I would approach this by tagging when the first goal is scored for each name. Then simply do a cumulative sum:
select cte.* except (seqnum), countif(seqnum = 1) over (order by date)
from (select cte.*,
(case when goals = 1 then row_number() over (partition by user, goals order by date) end) as seqnum
from cte
) cte;
I realize this can be expressed without the case in the subquery:
select cte.* except (seqnum), countif(seqnum = 1 and goals = 1) over (order by date)
from (select cte.*,
row_number() over (partition by user, goals order by date) as seqnum
from cte
) cte;

window function count aggregation

I have two quite complex queries going on here. Both should return per given country (Netherlands in this case) the monthly use over the total of 12 months and the percentage that makes up that month of the total of those 12 months.
But the one where i use count as a windowing function returns one more row than the one where i don't use the count as a windowing function.
The query for the left side picture is:
;WITH MonthUsage AS
(
SELECT customer_id, country_name, [Month], [Year], SUM(ItemsPerMonth)
AS ItemsPerMonth
FROM (
SELECT cs.country_name, c.customer_id, YEAR(mol.date_watched) AS Year, MONTH(mol.date_watched) AS [Month], COUNT(*) AS ItemsPerMonth
FROM Customer c
JOIN Customer_Subscription CS ON C.customer_id = CS.customer_id
JOIN Movie_Order_Line mol ON mol.customer_id = c.customer_id
WHERE (mol.date_watched BETWEEN '2017-07-01' AND '2018-07-01') AND cs.country_name = 'Nederland'
GROUP BY c.customer_id,cs.country_name, YEAR(mol.date_watched),
MONTH(mol.date_watched)
UNION ALL
SELECT cs.country_name, c.customer_id, YEAR(sol.date_watched) AS Year,
MONTH(sol.date_watched), COUNT(*) AS ItemsPerMonth
FROM Customer c
JOIN Customer_Subscription CS ON C.customer_id = CS.customer_id
JOIN Show_Order_Line sol ON sol.customer_id = c.customer_id
WHERE sol.date_watched BETWEEN '2017-07-01' AND '2018-07-01'
GROUP BY c.customer_id, cs.country_name, YEAR(sol.date_watched),
MONTH(sol.date_watched)
) AS MonthItems
WHERE country_name = 'Nederland'
GROUP BY customer_id, country_name, [Month], [Year]
),
Months(MonthNumber) AS
(
SELECT 1
UNION ALL
SELECT MonthNumber + 1
FROM months
WHERE MonthNumber < 12
)
SELECT cmb.[Year], ISNULL(cmb.[Month], m.MonthNumber) AS [Month],
ISNULL(ItemsPerMonth, 0) AS ItemsPerMonth,
ISNULL(FORMAT(((CAST(ItemsPerMonth AS decimal) / CAST((
SELECT SUM(ItemsPerMonth)
FROM MonthUsage) AS decimal
))),'P0'), '0%') AS [PercentageOfTotal]
FROM MonthUsage cmb
JOIN Customer c ON c.customer_id = cmb.customer_id
JOIN Months m ON m.MonthNumber = cmb.[Month]
ORDER BY cmb.[Year] ASC, [Month] ASC
And the query for the right picture is:
;WITH MonthUsage AS (
SELECT *
FROM (
SELECT
YEAR(date_watched) AS [Year],
MONTH(date_watched) AS [Month],
COUNT(order_id) OVER(PARTITION BY CONCAT(YEAR(date_watched), MONTH(date_watched))) AS ItemsPerMonth
FROM Movie_Order_Line mov
JOIN Customer c ON c.customer_id = mov.customer_id
JOIN Customer_Subscription cs ON C.customer_id = cs.customer_id
WHERE date_watched BETWEEN '2017-07-01' AND '2018-07-01' AND cs.country_name = 'Nederland'
UNION ALL
SELECT YEAR(date_watched) AS [Year], MONTH(date_watched) AS [Month], COUNT(order_id) OVER(PARTITION BY CONCAT(YEAR(date_watched), MONTH(date_watched))) AS ItemsPerMonth
FROM Show_Order_Line sol
JOIN Customer c ON c.customer_id = sol.customer_id
JOIN Customer_Subscription cs ON C.customer_id = cs.customer_id
WHERE date_watched BETWEEN '2017-07-01' AND '2018-07-01' AND cs.country_name = 'Nederland'
) AS Combined
GROUP BY [YEAR], [Month], ItemsPerMonth
)
SELECT *, ISNULL(FORMAT(((CAST(ItemsPerMonth AS decimal) / CAST((SELECT
SUM(ItemsPerMonth) FROM MonthUsage) AS decimal))),'P0'), '0%') AS
[PercentageOfTotal]
FROM MonthUsage
ORDER BY [Year] ASC, [Month] ASC
I can't seem to figure out why i'm getting different results. Any help is much appreciated. Thank you in advance for your time.

SQL YTD and last year YTD on complete data

I need to calculate YTD and last year YTD on a table [SQL Server 2012]. Below is the query I tried. Its getting doubled and tripled for some cases.
SELECT SUM(A.RevisionNumber)YTD,SUM(P.RevisionNumber)LY_YTD,B.OrderDateM,B.OrderDateY
FROM
(select MONTH(OrderDate)OrderDateM,YEAR(OrderDate)OrderDateY from sales.SalesOrderHeader B
group by MONTH(OrderDate),YEAR(OrderDate))B
LEFT JOIN
(select SUM(RevisionNumber)RevisionNumber,MONTH(OrderDate)OrderDateM,YEAR(OrderDate)OrderDateY
from sales.SalesOrderHeader
group by MONTH(OrderDate),YEAR(OrderDate))A
ON A.OrderDateM<=B.OrderDateM AND A.OrderDateY=B.OrderDateY
LEFT JOIN
(select SUM(RevisionNumber)RevisionNumber,MONTH(OrderDate)OrderDateM,YEAR(OrderDate)OrderDateY
from sales.SalesOrderHeader
group by MONTH(OrderDate),YEAR(OrderDate))P
ON P.OrderDateM<=B.OrderDateM AND P.OrderDateY=B.OrderDateY-1
GROUP BY B.OrderDateM,B.OrderDateY
ORDER BY B.OrderDateY,B.OrderDateM
You can use windowing function as below:
;With cte as (
Select Sum(RevisionNumber) As SM_RevisionNumber, Month(OrderDate) as OrderM,
Year(OrderDate) as OrderY
From Sales.SalesOrderHeader
Group by Month(OrderDate), Year(OrderDate)
), cte2 as (
Select YTD = Sum(SM_RevisionNumber) over (partition by OrderY order by OrderM),
OrderM, OrderY, RowN = Row_Number() over(order by OrderY, OrderM)
from cte
)
Select YTD, LY_YTD = lag(YTD, 12, null) over(Order by RowN), OrderM, ORderY
from cte2
But this solution assumes we have atleast one entry for each month and year.

Getting error on nested query

I'm trying to develop a time sheet page on my web site, and this is my database stracture:
I want to get total hours(TimeSheetWeeks table's sum(timeFrom-timeTo)), total expense(TimeSheetWeeks's table's total amount) and total(TimSheetWeeks table's total amount+ compAllow table's total Amount).
This is my query I wrote to get my result:
;WITH w(tot, tid, eid, fd, td, am, mw) AS
(
SELECT Total = tsw.amount+ca.amount , tsw.[TimeSheetID], [EmployeeID],
[FromDate],[ToDate], tsw.[Amount], SUM(DATEDIFF(MINUTE, [timeFrom],[timeTo] ))
FROM
TimeSheet ts
INNER JOIN (
SELECT SUM(amount) amount, TimeSheetID
FROM TimeSheetWeeks
GROUP BY TimeSheetID
) tsw ON ts.TimeSheetID = tsw.TimeSheetID INNER JOIN (
SELECT SUM(amount) amount, TimeSheetID
FROM CompAllow
GROUP BY TimeSheetID
) ca ON ts.TimeSheetID = ca.TimeSheetID INNER JOIN (
SELECT timeFrom, timeTo, TimeSheetID
FROM TimeSheetWeeks
) AS tss ON tss.TimeSheetID=ts.TimeSheetID
WHERE ts.TimeSheetID=6
Group By tsw.[TimeSheetID], [EmployeeID], [FromDate], [ToDate], tsw.[Amount]
)
SELECT tot, tid, eid, fd, td, Amount = am, totalHrs = RTRIM(mw/60) + ':' +
RIGHT('0'+ RTRIM(mw%60),2)
FROM w;
this quer causes an error saying
Column 'ca.amount' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
What goes wrong here? thanx in advance.
The ca.amount column is referenced in the w CTE, but is neither aggregated nor included in the GROUP BY clause:
;WITH w(tot, tid, eid, fd, td, am, mw) AS
(
SELECT Total = tsw.amount+ca.amount , tsw.[TimeSheetID], [EmployeeID],
[FromDate],[ToDate], tsw.[Amount], SUM(DATEDIFF(MINUTE, [timeFrom],[timeTo] ))
FROM
TimeSheet ts
INNER JOIN (
SELECT SUM(amount) amount, TimeSheetID
FROM TimeSheetWeeks
GROUP BY TimeSheetID
) tsw ON ts.TimeSheetID = tsw.TimeSheetID INNER JOIN (
SELECT SUM(amount) amount, TimeSheetID
FROM CompAllow
GROUP BY TimeSheetID
) ca ON ts.TimeSheetID = ca.TimeSheetID INNER JOIN (
SELECT timeFrom, timeTo, TimeSheetID
FROM TimeSheetWeeks
) AS tss ON tss.TimeSheetID=ts.TimeSheetID
WHERE ts.TimeSheetID=6
Group By tsw.[TimeSheetID], [EmployeeID], [FromDate], [ToDate], tsw.[Amount]
)
SELECT tot, tid, eid, fd, td, Amount = am, totalHrs = RTRIM(mw/60) + ':' +
RIGHT('0'+ RTRIM(mw%60),2)
FROM w;
Either add it to GROUP BY or change the Total expression like this:
Total = tsw.amount + SUM(ca.amount)
depending upon what is the business rule for this query.
The error states the problem:
SELECT SUM(amount) amount, TimeSheetID
FROM CompAllow
GROUP BY TimeSheetID
) ca ...
I'm not 100% sure, but my initial recommendation is to drop the "group by" in this clause. At best, it's redundant.
I'd also recommend trying each of the subclauses separately - make sure they're syntactically correct, make sure they're returning expected results.
IMHO...