Subqueries Condition (SQL) - sql

So i want to create a view using the below script the problem is i want to show the view for 2020 grouped by quarter as you can see i have 2 subqueries using to_char(ACTION_DATE,'YYYY') = 2020 I want to return quarter results ONLY if FileNO's in both subqueries are from the Same Quarter.
SELECT Quarter,
count(FileNO), avg(total_time),
sum( case when Total_Time <= :T Then 1 Else 0 End ) Achieved,
sum( case when Total_Time <= :T Then 1 Else 0 End ) / Count(FileNO) * 100 Precentage_Acheived
from
(SELECT to_Char(ACTION_DATE,'YYYYQ') as Quarter, FileNO, SUM(work_time) as total_time
FROM F.MV
WHERE
(FileNO, APP_no) IN
(SELECT FileNO, APP_no
FROM F.MV
WHERE to_char(ACTION_DATE,'YYYY') = 2020
AND TASK_NAME = 'Lifting'
AND TO_TASK_NAME = 'Finish')
AND DEPT_NAME = 'TempDep'
AND WF_TASK_NAME = 'Lifting'
and to_char(ACTION_DATE,'YYYY') = 2020
GROUP BY to_Char(ACTION_DATE,'YYYYq'),FileNO
)
GROUP BY Quarter
Correct if i use to_char(ACTION_DATE,'YYYYQ') = 20201 for both subquieres
but result iam getting with to_char(ACTION_DATE,'YYYY') = 2020 is:
Thanks

I think the innermost correlation clause you want is:
(FileNO, APP_no) IN
(SELECT mv2.FileNO, mv2.APP_no
FROM F.MV mv2
WHERE to_char(mv2.ACTION_DATE, 'YYYYQ') = to_char(mv.ACTION_DATE, 'YYYYQ')

Related

POSTGRESQL GROUP BY QUERY

SELECT
concat(
EXTRACT(
YEAR
FROM
"BEAUFTRAGUNG_DATUM"
),
'-',
TO_CHAR(
EXTRACT(
MONTH
FROM
"BEAUFTRAGUNG_DATUM"
),
'fm00'
)
) AS "DATUM",
CASE
WHEN (
"STATUS" in (
'....', '...'
)
) THEN 'OTHER'
WHEN ("STATUS" = 'BESTELLT') THEN 'BESTELLT'
WHEN ("STATUS" = 'VOR_PRODUKTION') THEN 'VOR_PRODUKTION'
END AS "MODIFIED_STATUS",
COUNT(*) AS "ANZAHL"
FROM
PUBLIC."TXS"
WHERE
"FLAG_POS" = '1'
GROUP BY
"DATUM",
"MODIFIED_STATUS"
ORDER BY
"DATUM" ASC
This is what I have.
And I want it like this
DATUM OTHER BESTELLT VOR_PRODUKTION
2021-11 47 87 366
2022-01 1 0 0
2022-02 82 73 356
So that I have unique dates.
Thanks in advance.
I tried some solutions with "JOINS" but none of them worked.
I hope that you have any ideas...
This query should be able to get the desired result with the given information:
SELECT
txs.DATUM,
COALESCE(other.sum, 0) AS other,
COALESCE(bestellt.sum, 0) AS bestellt,
COALESCE(vor_produktion.sum, 0) AS vor_produktion
FROM
PUBLIC."TXS" txs
LEFT JOIN (SELECT tsx2.DATUM, SUM(tsx2.ANZAHL) AS sum FROM PUBLIC."TXS" tsx2 WHERE tsx2.MODIFIED_STATUS = 'OTHER' GROUP BY tsx2.DATUM) other ON other.DATUM = txs.DATUM
LEFT JOIN (SELECT tsx2.DATUM, SUM(tsx2.ANZAHL) AS sum FROM PUBLIC."TXS" tsx2 WHERE tsx2.MODIFIED_STATUS = 'BESTELLT' GROUP BY tsx2.DATUM) bestellt ON bestellt.DATUM = txs.DATUM
LEFT JOIN (SELECT tsx2.DATUM, SUM(tsx2.ANZAHL) AS sum FROM PUBLIC."TXS" tsx2 WHERE tsx2.MODIFIED_STATUS = 'VOR_PRODUKTION' GROUP BY tsx2.DATUM) vor_produktion ON vor_produktion.DATUM = txs.DATUM
GROUP BY txs.DATUM, other.sum, bestellt.sum, vor_produktion.sum
Here we left join the 3 columns with a subquery and replaces <null> values with 0

SQL - Calculate percentage by group, for multiple groups

I have a table in GBQ in the following format :
UserId Orders Month
XDT 23 1
XDT 0 4
FKR 3 6
GHR 23 4
... ... ...
It shows the number of orders per user and month.
I want to calculate the percentage of users who have orders, I did it as following :
SELECT
HasOrders,
ROUND(COUNT(*) * 100 / CAST( SUM(COUNT(*)) OVER () AS float64), 2) Parts
FROM (
SELECT
*,
CASE WHEN Orders = 0 THEN 0 ELSE 1 END AS HasOrders
FROM `Table` )
GROUP BY
HasOrders
ORDER BY
Parts
It gives me the following result:
HasOrders Parts
0 35
1 65
I need to calculate the percentage of users who have orders, by month, in a way that every month = 100%
Currently to do this I execute the query once per month, which is not practical :
SELECT
HasOrders,
ROUND(COUNT(*) * 100 / CAST( SUM(COUNT(*)) OVER () AS float64), 2) Parts
FROM (
SELECT
*,
CASE WHEN Orders = 0 THEN 0 ELSE 1 END AS HasOrders
FROM `Table` )
WHERE Month = 1
GROUP BY
HasOrders
ORDER BY
Parts
Is there a way execute a query once and have this result ?
HasOrders Parts Month
0 25 1
1 75 1
0 45 2
1 55 2
... ... ...
SELECT
SIGN(Orders),
ROUND(COUNT(*) * 100.000 / SUM(COUNT(*), 2) OVER (PARTITION BY Month)) AS Parts,
Month
FROM T
GROUP BY Month, SIGN(Orders)
ORDER BY Month, SIGN(Orders)
Demo on Postgres:
https://dbfiddle.uk/?rdbms=postgres_10&fiddle=4cd2d1455673469c2dfc060eccea8020
You've stated that it's important for the total to be 100% so you might consider rounding down in the case of no orders and rounding up in the case of has orders for those scenarios where the percentages falls precisely on an odd multiple of 0.5%. Or perhaps rounding toward even or round smallest down would be better options:
WITH DATA AS (
SELECT SIGN(Orders) AS HasOrders, Month,
COUNT(*) * 10000.000 / SUM(COUNT(*)) OVER (PARTITION BY Month) AS PartsPercent
FROM T
GROUP BY Month, SIGN(Orders)
ORDER BY Month, SIGN(Orders)
)
select HasOrders, Month, PartsPercent,
PartsPercent - TRUNCATE(PartsPercent) AS Fraction,
CASE WHEN HasOrders = 0
THEN FLOOR(PartsPercent) ELSE CEILING(PartsPercent)
END AS PartsRound0Down,
CASE WHEN PartsPercent - TRUNCATE(PartsPercent) = 0.5
AND MOD(TRUNCATE(PartsPercent), 2) = 0
THEN FLOOR(PartsPercent) ELSE ROUND(PartsPercent) -- halfway up
END AS PartsRoundTowardEven,
CASE WHEN PartsPercent - TRUNCATE(PartsPercent) = 0.5 AND PartsPercent < 50
THEN FLOOR(PartsPercent) ELSE ROUND(PartsPercent) -- halfway up
END AS PartsSmallestTowardZero
from DATA
It's usually not advisable to test floating-point values for equality and I don't know how BigQuery's float64 will work with the comparison against 0.5. One half is nevertheless representable in binary. See these in a case where the breakout is 101 vs 99. I don't have immediate access to BigQuery so be aware that Postgres's rounding behavior is different:
https://dbfiddle.uk/?rdbms=postgres_10&fiddle=c8237e272427a0d1114c3d8056a01a09
Consider below approach
select hasOrders, round(100 * parts, 2) as parts, month from (
select month,
countif(orders = 0) / count(*) `0`,
countif(orders > 0) / count(*) `1`,
from your_table
group by month
)
unpivot (parts for hasOrders in (`0`, `1`))
with output like below

Simplify complex Query

I need to simplify a complex old query in order to filter is with date range.
I got a table with Tickets and TicketNotes.
I need
a column with the Tickets count of the day
a column with the Tickets count with a specific note of the day
the date
The old query
SELECT SUM(IFNULL(qtickets.count, 0)) j, SUM(IFNULL(mtickets.count, 0)) m FROM (
SELECT
COUNT(tickets.id) COUNT,
DATE(tickets.date) DATE
FROM
tickets
WHERE
tickets.status = 'Closed' AND tickets.did = 7
AND MONTH(tickets.date) = MONTH( CURRENT_DATE - INTERVAL 1 MONTH )
AND YEAR(tickets.date) = YEAR( CURRENT_DATE - INTERVAL 1 MONTH )
GROUP BY
DATE(tickets.date)
) AS mtickets LEFT JOIN (
SELECT
1 AS COUNT,
DATE(tickets.date) DATE
FROM
ticketnotes
INNER JOIN tickets ON tickets.id = ticketnotes.ticketid
WHERE
ticketnotes.message LIKE '%https://xxxxx.net/help/tickets/%'
AND tickets.status = 'Closed'
AND tickets.did = 7
AND MONTH(tbltickets.date) = MONTH( CURRENT_DATE - INTERVAL 1 MONTH )
AND YEAR(tbltickets.date) = YEAR( CURRENT_DATE - INTERVAL 1 MONTH )
GROUP BY
DATE(tickets.date)
) AS qtickets ON (mtickets.date = qtickets.date)
The goal is to get a result of
Date | M | Q
===================
2020-04-01 | 1 | 1
2020-04-02 | 2 | 1
2020-04-03 | 5 | 2
...
2020-04-30 | 3 | 0
With M be the total closed tickets of the day for did = 7 and Q be the total closed tickets that got the note.message.
I need to check the query with one instance of date filter date BETWEEN '2020-04-01' AND '2020-04-30' and still get the correct three columns.
=======
UPDATE:
When I'm trying to add AND DATE(tickets.date) BETWEEN DATE('2020-04-01') AND DATE('2020-04-30') in Gordon's answer, I got other result data from my primary query.
QUERY:
SELECT
DATE(t.date),
COUNT(t.id) AS num_tickets,
(CASE WHEN COUNT(tn.ticketid) = 0 THEN 0 ELSE 1 END) AS num_with_message
FROM
tickets t
LEFT JOIN ticketnotes tn ON
tn.ticketid = t.id AND tn.message LIKE '%https://xxxxx.net/help/tickets/%'
WHERE
t.status = 'Closed' AND t.did = 7
AND DATE(t.date) BETWEEN DATE('2020-04-01') AND DATE('2020-04-30')
GROUP BY
DATE(t.date)
The result is getting num_tickets with wrong data as getting num_ticket without JOIN.
Any suggestions ?
You could try using case for the ehere like
SELECT
DATE(tickets.date) DATE
, COUNT(tickets.id) M
, case sum( ticketnotes.message LIKE '%https://xxxxx.net/help/tickets/%' <> 0 ) then 1 else null end Q
FROM
ticketnotes
INNER JOIN tickets ON tickets.id = ticketnotes.ticketid
WHERE tickets.status = 'Closed'
AND tickets.did = 7
AND MONTH(tbltickets.date) = MONTH( CURRENT_DATE - INTERVAL 1 MONTH )
AND YEAR(tbltickets.date) = YEAR( CURRENT_DATE - INTERVAL 1 MONTH )
GROUP BY DATE(tickets.date)
This answers the original version of the question.
What you are describing sounds like a group by with left join. However, it is not clear what exactly you are looking for. My best guess is:
select date(t.date), count(t.id) as num_tickets,
count(tn.ticketid) as num_with_message
from tickets t left join
ticketnotes tn
on tn.ticketid = t.id and
tn.message like '%https://xxxxx.net/help/tickets/%'
where t.status = 'Closed' and
t.did = 7
group by date(t.date)

query to select count of records for each year

sorry for this newbie question ... im trying to get number of rows per year of my table..... this is my try:
select count(*)
from tbl_fact
where stat = 1 and id = 16
group by (year(fact_date))
go
and
select count(*)
from tbl_fact
where stat = 1 and id = 16 and year(fact_date) in (select Distinct(year(fact_date)) from tbl_fact)
group by (year(fact_date))
go
i have records that taged with dates that for now i have dates from 2017 and 2018 so i need counts for each year. but the id=16 has only date tag of 2018 not 2017 so i get result as
eg: 15
how ever it should be like
eg: 0 //2017
15 //2018
A simple method to get all years in the data -- even when they don't meet the conditions of the where clause -- is to use conditional aggregation:
select year(fact_date) as yyyy,
sum(case when stat = 1 and id = 16 then 1 else 0 end) as cnt_16
from tbl_fact
group by year(fact_date)
order by yyyy;
You can get the count and year in two columns by:
select
count(*) as [COUNT],
year(fact_date) as [Year]
from tbl_fact
where stat = 1 and id = 16
group by (year(fact_date));
or as one string
select
count(*) + ' // ' + year(fact_date) as [grouping]
from tbl_fact
where stat = 1 and id = 16
group by (year(fact_date));
SELECT CAST([CountPerYear] AS VARCHAR(10))
+ ' // ' +
CAST([Year] AS VARCHAR(10))
FROM
(
select year(fact_date) [Year]
, count(*) [CountPerYear]
from tbl_fact
where stat = 1 and id = 16
group by year(fact_date)
)x

Bring through a newly created calculated column in another query

I have 2 separate queries below which run correctly.Now I've created a calculated column to provide a count of working days by YMs and would like to bring this through to query1(the join would be query1.Period = query2.Yms)
please see the query and outputs below.
SELECT Client, ClientGroup, Type, Value, Period, PeriodName, PeriodNumber, ClientName
FROM metrics.dbo.vw_KPI_001_Invoice
select YMs,sum(case when IsWorkDay = 'X' then 1 else 0 end) from IESAONLINE.Dbo.DS_Dates
where Year > '2013'
group by YMs
Query 1
Client ClientGroup Type Value Period PeriodName PeriodNumber ClientName
0LG0 KarroFoods Stock 5691.68 201506 Week 06 2015 35 Karro Foods Scunthorpe
Query 2
YMs (No column name)
201401 23
Would the following work:
SELECT Client, ClientGroup, Type, Value, Period, PeriodName, PeriodNumber, ClientName, cnt
FROM metrics.dbo.vw_KPI_001_Invoice q1
INNER JOIN (select YMs,sum(case when IsWorkDay = 'X' then 1 else 0 end) as cnt from IESAONLINE.Dbo.DS_Dates
where Year > '2013'
group by YMs ) q2 ON q1.Period = q2.YMs
If a value isn't always available then you might consider changing the INNER JOIN to an OUTER JOIN.