I have been having trouble finding the result for this problem.
Below are my table structure details:
studios
(
studio_id,
location
)
photo_sessions
(
session_id,
studio_id,
cust_id,
session_length,
session_date
)
customer
(
cust_id,
cus_first,
cus_last,
emailid
)
order
(
order_id,
cust_id,
order_description,
amount
)
package_order
(
package_order_id,
order_id,
package_id,
price,
quantity
)
package
(
package_id,
package_name
)
I would like to find which package is ordered most often at each location.
I tried this query,
SELECT
p.package_name,
s.location,
count(p.package_id)
FROM package p,
package_order po,
order_table o,
customer c,
photo_sessions ps,
studios s
WHERE p.package_id=po.package_id
and po.order_id=o.order_id
and o.cust_id=c.cust_id
and c.cust_id=ps.cust_id
and ps.studio_id=s.studio_id
GROUP BY p.package_name,
s.location
HAVING COUNT (p.package_id)=
(
SELECT MAX(mycount)
FROM (
SELECT package_id, COUNT(package_id) as mycount
FROM package_order
GROUP BY package_id
) as most_order
);
I am not sure it gives the right result. Any help will be appreciated.
You can do this with window functions:
WITH cte as (
SELECT
p.package_name,
s.location,
count(p.package_id) AS mycount,
row_number() over(partition by s.location order by count(p.package_id) desc) AS rn
FROM package p
JOIN package_order po ON p.package_id = po.package_id
JOIN order_table o ON po.order_id = o.order_id
JOIN customer c ON o.cust_id = c.cust_id
JOIN photo_sessions ps ON c.cust_id = ps.cust_id
JOIN studios s ON ps.studio_id = s.studio_id
GROUP BY p.package_name,
s.location)
SELECT * FROM cte
WHERE rn = 1
PS: you use Sql Server 2012 but joining with old style deprecated syntax. It is time to forget about old one.
EDIT:
WITH cte as (
SELECT
p.package_name,
s.location,
count(p.package_id) AS mycount
FROM package p
JOIN package_order po ON p.package_id = po.package_id
JOIN order_table o ON po.order_id = o.order_id
JOIN customer c ON o.cust_id = c.cust_id
JOIN photo_sessions ps ON c.cust_id = ps.cust_id
JOIN studios s ON ps.studio_id = s.studio_id
GROUP BY p.package_name,
s.location)
SELECT * FROM cte c1
CROSS APPLY(SELECT MAX(mycount) mycount FROM cte c2 WHERE c1.location = c2.location) ca
WHERE c1.mycount = ca.mycount
Related
I have been trying to use LEFT OUTER JOIN, GROUP BY and (failing) to use the CONCAT || function to get the maximum score for the best book of the decade but have had no luck finding out when two books get the same max score in the same decade.
I need the output below:
There are 2 tables:
Table 1: bookName
Schema: uniqueBookNameId, BookName, yearPublished (from 1901 to 2022)
Table 2: bookRating
Schema: uniqueBookNameId, bookRating
Use a CTE where you join the tables and rank the books with RANK() window function.
Then filter the results to get the top books of each decade:
WITH cte AS (
SELECT r.bookRating,
n.BookName,
n.yearPublished / 10 * 10 || 's' AS Decade,
RANK() OVER (PARTITION BY n.yearPublished / 10 * 10 ORDER BY r.bookRating DESC) AS rnk
FROM bookName n INNER JOIN bookRating r
ON r.uniqueBookNameId = n.uniqueBookNameId
)
SELECT DISTINCT bookRating, BookName, Decade
FROM cte
WHERE rnk = 1
ORDER BY Decade;
or:
WITH cte AS (
SELECT r.bookRating,
n.BookName,
n.yearPublished / 10 * 10 || 's' AS Decade,
RANK() OVER (PARTITION BY n.yearPublished / 10 * 10 ORDER BY r.bookRating DESC) AS rnk
FROM bookName n INNER JOIN bookRating r
ON r.uniqueBookNameId = n.uniqueBookNameId
)
SELECT bookRating, GROUP_CONCAT(DISTINCT BookName) AS BookName, Decade
FROM cte
WHERE rnk = 1
GROUP BY Decade
ORDER BY Decade;
I'm very new to learning SQL, I apologize if my question isn't completely accurate.
The question I'm trying to answer with this query is "What is the most popular music genre in each country?" I've had to use a subquery and it works, but I found that for a few countries in the table, more than one genre has the MAX value. I'm stuck with how to edit my query so that all genres with the max value show in the results. Here is my code, using DB Browser for SQLite:
SELECT BillingCountry AS Country , name AS Genre , MAX(genre_count) AS Purchases
FROM (
SELECT i.BillingCountry, g.name, COUNT(g.genreid) AS genre_count
FROM Invoice i
JOIN InvoiceLine il
ON il.InvoiceId = i.InvoiceId
JOIN TRACK t
ON il.trackid = t.TrackId
JOIN Genre g
ON t.genreid = g.GenreId
GROUP BY 1,2
) sub
GROUP BY 1
Here is an example of the result:
| Country | Genre |Purchase|
|---------|-------|--------|
|Agrentina| Punk | 9 |
|Australia| Rock | 22 |
BUT in running just the subquery to COUNT the purchases, Argentina has two Genres with 9 Purchases (the max number for that country). How do I adjust my query to include both and not just the first one in the row?
You can do it with RANK() window function:
SELECT BillingCountry, name, genre_count
FROM (
SELECT i.BillingCountry, g.name, COUNT(*) AS genre_count,
RANK() OVER (PARTITION BY i.BillingCountry ORDER BY COUNT(*) DESC) rnk
FROM Invoice i
INNER JOIN InvoiceLine il ON il.InvoiceId = i.InvoiceId
INNER JOIN TRACK t ON il.trackid = t.TrackId
INNER JOIN Genre g ON t.genreid = g.GenreId
GROUP BY i.BillingCountry, g.name
)
WHERE rnk = 1
This will return the ties in separate rows.
If you want 1 row for each country, you could also use GROUP_CONCAT():
SELECT BillingCountry, GROUP_CONCAT(name) AS name, MAX(genre_count) AS genre_count
FROM (
SELECT i.BillingCountry, g.name, COUNT(*) AS genre_count,
RANK() OVER (PARTITION BY i.BillingCountry ORDER BY COUNT(*) DESC) rnk
FROM Invoice i
INNER JOIN InvoiceLine il ON il.InvoiceId = i.InvoiceId
INNER JOIN TRACK t ON il.trackid = t.TrackId
INNER JOIN Genre g ON t.genreid = g.GenreId
GROUP BY i.BillingCountry, g.name
)
WHERE rnk = 1
GROUP BY BillingCountry
In this query, I want to use with-statement. I have a subquery that calculates A union all B and I want to use it with with-statement. But when I use with-statement I face the error that says "table or view does not exist".
what surprises me is when I replace the first part with with-statement it works correctly. But when I replace the second part, I face this error!!
select
deposit.BRNCH_COD||'-'||deposit.DP_TYPE_COD||''||deposit.CUSTOMER_NUM||'-
'||deposit.DEPOSIT_SERIAL AS DEPOSIT_NUMBER,
deposit.IBAN AS IBAN,
deposit.CURRENCY_DESC AS DEPOSIT_CURRCOD,
deposit.BRNCH_COD AS BRNCH_COD,
MAIN_7.Still_Days
AS Still_Lenght,
to_char(MAIN_7.Startdate, 'yyyy/mm/dd' ,'nls_calendar=persian') AS
START_DATE,
MAIN_7.AMOUNT
AS TOTAL_AMOUNT,
MAIN_7.TRN_Count
AS TRN_Count
from
(
select Trans_Table.DEPOSIT_KEY AS DEPOSIT_KEY,
Trans_Table.TRN_Start_DATE AS Startdate,
MAX(Active_Time_Table.EFFECTIVE_DATE) AS Lastdate,
H.PASSIVE_DAYS AS Still_Days,
SUM(Active_Time_Table.AMOUNT) AS AMOUNT,
Count(Active_Time_Table.AMOUNT) AS TRN_Count
from
(
Select F.DEPOSIT_KEY,
SUM (F.AMOUNT) AS TRN_AMOUNT,
MIN (F.EFFECTIVE_DATE) AS TRN_Start_DATE
from
(
A
union all
B
)F
Group by (F.DEPOSIT_KEY)
Having ( SUM (F.AMOUNT) >10000000000)
)Trans_Table
inner join
H
on (Trans_Table.DEPOSIT_KEY = H.DEPOSIT_KEY and
Trans_Table.TRN_Start_DATE-1 = H.EFFECTIVE_DATE)
inner join
(
A
union all
B
)Active_Time_Table
on (Trans_Table.DEPOSIT_KEY = Active_Time_Table.DEPOSIT_KEY and
Active_Time_Table.EFFECTIVE_DATE - Trans_Table.TRN_Start_DATE< 4 and
Active_Time_Table.EFFECTIVE_DATE - Trans_Table.TRN_Start_DATE>=0)
group by ( Trans_Table.DEPOSIT_KEY ,
Trans_Table.TRN_Start_DATE,H.PASSIVE_DAYS)
Having (SUM(Active_Time_Table.AMOUNT)) > 10000000000
)MAIN_7
inner join dimamldeposit deposit
on deposit.DEPOSIT_KEY = MAIN_7.DEPOSIT_KEY
***********************************************************
with rep as
(A union all B)
select
deposit.BRNCH_COD||'-'||deposit.DP_TYPE_COD||'-
'||deposit.CUSTOMER_NUM||'-'||deposit.DEPOSIT_SERIAL AS DEPOSIT_NUMBER,
deposit.IBAN AS IBAN,
deposit.CURRENCY_DESC AS DEPOSIT_CURRCOD,
deposit.BRNCH_COD AS BRNCH_COD,
MAIN_7.Still_Days AS Still_Lenght,
to_char(MAIN_7.Startdate, 'yyyy/mm/dd' ,'nls_calendar=persian') AS START_DATE,
MAIN_7.AMOUNT AS TOTAL_AMOUNT,
MAIN_7.TRN_Count AS TRN_Count
from
(
select Trans_Table.DEPOSIT_KEY AS DEPOSIT_KEY,
Trans_Table.TRN_Start_DATE AS Startdate,
MAX(rep.EFFECTIVE_DATE) AS Lastdate,
H.PASSIVE_DAYS AS Still_Days,
SUM(rep.AMOUNT) AS AMOUNT,
Count(rep.AMOUNT) AS TRN_Count
from
(
Select rep.DEPOSIT_KEY,
SUM (rep.AMOUNT) AS TRN_AMOUNT,
MIN (rep.EFFECTIVE_DATE) AS TRN_Start_DATE
from
rep
Group by (rep.DEPOSIT_KEY)
Having ( SUM (rep.AMOUNT) >10000000000)
)Trans_Table
inner join
H
on (Trans_Table.DEPOSIT_KEY = H.DEPOSIT_KEY and Trans_Table.TRN_Start_DATE-1 = H.EFFECTIVE_DATE)
inner join
rep rep
on (Trans_Table.DEPOSIT_KEY = rep.DEPOSIT_KEY and rep.EFFECTIVE_DATE - Trans_Table.TRN_Start_DATE< 4 and rep.EFFECTIVE_DATE - Trans_Table.TRN_Start_DATE>=0)
group by ( Trans_Table.DEPOSIT_KEY , Trans_Table.TRN_Start_DATE,H.PASSIVE_DAYS)
Having (SUM(rep.AMOUNT)) > 10000000000
)MAIN_7
inner join dimamldeposit deposit
on deposit.DEPOSIT_KEY = MAIN_7.DEPOSIT_KEY
That's a lot of code, but - to make it simple, I'd suggest you use WITH factoring clause as the first command, include all tables you use into it, and then - as the final SELECT - fetch data from all those CTEs. Something like this:
with
a as (select ... from ...),
b as (select ... from ...),
f as (select ... from ...),
...
select a.col1, b.col2, f.col3
from a join b on a.id = b.id
left join f on f.id = b.id
where ...
In DB2 is there a way to basically say:
case when sku (select * from table1 where tb1field = 'SMOMD') then 'True' end
Okay so this is my query so far, I've been going at this for at least a month now so any help would be great.
select tb4.customer, tb4.sku, tb4.qty, tb4.retqty, tb4.stipqty, tb4.lastdate, tb4.firstdate, tb4.stipdate
from(
--Table 4
select tb3.Customer as Customer, tb3.sku as SKU, tb3.qty as Qty, tb3.retqty as RetQty, tb3.stipqty as STIPQty,
case when tb3.lastdate is null then '00/0000' else substr(tb3.lastdate,5,2)||'/'||substr(tb3.lastdate,1,4) end as LastDate,
case when tb3.firstdate is null then '00/0000' else substr(tb3.firstdate,5,2)||'/'||substr(tb3.firstdate,1,4) end as FirstDate,
case when tb3.stipdate is null then '00/0000' else substr(tb3.stipdate,5,2)||'/'||substr(tb3.stipdate,1,4) end as STIPDate
from(
--Table 3
select tb2.Customer as Customer, tb2.SKU as SKU, tb2.Qty as Qty, tb2.RetQty as RetQty, tb2.STIPQty as STIPQty,
max(case when tb2.TranID in ('010','100') then tb2.datenum end) as LastDate,
min(case when tb2.TranID in ('010','100') then tb2.datenum end) as FirstDate,
case when tb2.RC = '4M' then tb2.datenum end as STIPDate
from(
--Table 2
select tb1.Customer as Customer, tb1.SKU as SKU,
sum(case when tb1.TranID in ('010','100') then abs(tb1.OrdNet) else '0' end) as Qty,
sum(case when tb1.TranID = '500' and tb1.rc != '4M' then abs(tb1.OrdNet) else '0' end) as RetQty,
count(case when tb1.rc = '4M' then tb1.sku end) as STIPQty,
tb1.datenum as datenum, tb1.TranID as tranid, tb1.RC as rc
from(
--Table 1
select distinct stkund as Customer, sthptg||space(1)||stmodl||space(1)||stvari||space(1)||stfarb||space(1)||stgroe as SKU,
stvorg as TranID, stggru as RC, stprg09 as PG9, stprg08 as PG8, stperi as datenum, ormne1 as OrdNet
from st_usus.s_stati_pv
join caspdtau.cospf440 on stadrn = jadr40
where trim(stvert) in ('111S','122S')
and sthptg != 'V'
and aktv40 = 'A'
and stprg01 in ('01','04')
and stprg02 = '01'
and stvorg in ('500','010','100')
and stperi >= '20160100'
) as tb1
group by tb1.Customer, tb1.SKU, tb1.datenum, tb1.tranid, tb1.rc
) as tb2
group by tb2.customer, tb2.sku, tb2.qty, tb2.retqty, tb2.stipqty, tb2.tranid, tb2.rc, tb2.datenum
) as tb3
group by tb3.customer, tb3.sku, tb3.qty, tb3.retqty, tb3.stipqty, tb3.lastdate, tb3.firstdate, tb3.stipdate
) as tb4
order by tb4.Customer, tb4.sku
I'm not going to try to decipher exactly what you're trying to do...
Some general advice, rather than using Nested Table Expressions (NTE)
select <..> from (select <...>from mytable)
Consider Common Table Expressions (CTE)
with
table1 as (select <...> from st_usus.s_stati_pv join caspdtau.cospf440 on stadrn = jadr40)
, table2 as (select <...> from table1)
, table3 as (select <...> from table2)
, table4 as (select <....> from table3)
select <...> from table4;
Each CTE (ie. tableX) can refer to a prior CTE or a physical table/view as needed. The final select can refer to one or more CTE's along with one or more physical tables or views.
Nice thing about building with CTE's, is that you can check your results after each step..
with
table1 as (select <...> from st_usus.s_stati_pv join caspdtau.cospf440 on stadrn = jadr40)
select * from table1;
I'm working in Teradata to Oracle migration project. How can i modify the below query which is using QUALIFY in Teradata.
//QUERY 1
SELECT S.ID as Id,
S.MP_CD as Code,
S.GM_CD as GmCode,
S.GM_MSR_NBR as Mea_Year,
S.STTS_CD as YearCode,
S.TRMNTN_DTM as TerminationDate
FROM PD.RVY S, LOAD_LOG TLL
WHERE S.UPDTD_LOAD = TLL.LOG_KEY AND TLL.BLSH_CD = 'Y' AND S.STTS_CD IN ( 'C', 'P' )
QUALIFY ROW_NUMBER () OVER (PARTITION BY S.GM_CD ,S.MP_CD ,S.GM_MSR_NBR,S.STTS_CD
ORDER BY S.SO_DTM DESC
) = 1;
//Query 2
SELECT SP.ID,
SP.SO_DTM,
SP.TAX_ID,
SP.USER_ID,
SP.FRST_NM,
SP.LAST_NM,
SP.PHONE_NBR,
QSRP.TAX_ID,
QSRP.ROW_ID,
MAX(SP.SO_DTM) OVER (PARTITION BY SP.ID, SP.TAX_ID) MAX_SO_DTM
FROM VOPR_RMSY SP,VOPR_RMSY_SPNS QSRP
WHERE SP.ID =:URVYID AND QSRP.TAX_ID =:RPAXID
AND SP.ID = QSRP.ID AND SP.TAX_ID = QSRP.TAX_ID AND SP.SO_DTM = QSRP.SO_DTM
QUALIFY (SP.SO_DTM=MAX_SO_DTM AND QSRP.SO_DTM = MAX_SO_DTM)
GROUP BY SP.ID,SP.SO_DTM,SP.TAX_ID,SP.USER_ID,SP.FRST_NM,SP.LAST_NM,SP.PHONE_NBR,
QSRP.TAX_ID,QSRP.ROW_ID;
For this tried with HAVING instead of qualify but got an Error:
ORA-00904: "MAX_SO_DTM": invalid identifier
00904. 00000 - "%s: invalid identifier"
Seems like alias used for MAX is not working here....
Any of your help is really appreciated!
EDITED:
SELECT * FROM
(
SP.ID,
SP.SO_DTM,
SP.TAX_ID,
SP.USER_ID,
SP.FRST_NM,
SP.LAST_NM,
SP.PHONE_NBR,
QSRP.TAX_ID,
QSRP.ROW_ID,
MAX(SP.SO_DTM) OVER (PARTITION BY SP.ID, SP.TAX_ID) AS MAX_SO_DTM
FROM VOPR_RMSY SP,VOPR_RMSY_SPNS QSRP
WHERE SP.ID =:URVYID AND QSRP.TAX_ID =:RPAXID AND SP.ID = QSRP.ID AND SP.TAX_ID =
QSRP.TAX_ID AND SP.SO_DTM = QSRP.SO_DTM
GROUP BY SP.ID,SP.SO_DTM,SP.TAX_ID,SP.USER_ID,SP.FRST_NM,SP.LAST_NM,SP.PHONE_NBR,
QSRP.TAX_ID,QSRP.ROW_ID;
)dt WHERE (SP.SO_DTM=MAX_SO_DTM AND QSRP.SO_DTM = MAX_SO_DTM)
i know that i have to use alias dt for outer WHERE instead of SP and QSRP but here MAX_SO_DTM is compared with SO_DTM from two different tables. is there any other way to modify this?
Thanks!
Both QUALIFY and reusing an alias is Teradata specific.
Your try with HAVING is failing, because this is the logical sequence of processing a query:
FROM
WHERE
GROUP BY
HAVING
OLAP-function
QUALIFY -- Teradata specific
SAMPLE or EXPAND ON -- both are Teradata specific
ORDER
To resolve this you have to use a Derived Table/Inline View and move the QUALIFY condition into the outer WHERE.
SELECT *
FROM
(
SELECT S.ID as Id,
S.MP_CD as Code,
S.GM_CD as GmCode,
S.GM_MSR_NBR as Mea_Year,
S.STTS_CD as YearCode,
S.TRMNTN_DTM as TerminationDate,
ROW_NUMBER () OVER (PARTITION BY S.GM_CD ,S.MP_CD ,S.GM_MSR_NBR,S.STTS_CD
ORDER BY S.SO_DTM DESC) AS rn
FROM PD.RVY S, LOAD_LOG TLL
WHERE S.UPDTD_LOAD = TLL.LOG_KEY AND TLL.BLSH_CD = 'Y' AND S.STTS_CD IN ( 'C', 'P' )
) dt
WHERE rn = 1;
The same technique must be used when you want to reuse an alias.
EDIT:
The 2nd query can be rewritten as:
SELECT *
FROM
(
SELECT
SP.ID,
SP.SO_DTM,
SP.TAX_ID,
SP.USER_ID,
SP.FRST_NM,
SP.LAST_NM,
SP.PHONE_NBR,
QSRP.TAX_ID,
QSRP.ROW_ID,
MAX(SP.SO_DTM) OVER (PARTITION BY SP.ID, SP.TAX_ID) AS MAX_SO_DTM
FROM VOPR_RMSY SP,VOPR_RMSY_SPNS QSRP
WHERE SP.ID =:URVYID
AND QSRP.TAX_ID =:RPAXID
AND SP.ID = QSRP.ID
AND SP.TAX_ID = QSRP.TAX_ID
AND SP.SO_DTM = QSRP.SO_DTM
GROUP BY SP.ID,SP.SO_DTM,SP.TAX_ID,SP.USER_ID,SP.FRST_NM,SP.LAST_NM,SP.PHONE_NBR,
QSRP.TAX_ID,QSRP.ROW_ID
)dt
WHERE SO_DTM=MAX_SO_DTM
You don't need to do both comparisons *(SP.SO_DTM=MAX_SO_DTM AND QSRP.SO_DTM = MAX_SO_DTM)*, because they the 2nd is redundant as the tables are joined on *SP.SO_DTM = QSRP.SO_DTM*.
Otherwise you had to add QSRP.SO_DTM to the Derived Table using a different alias (e.g. QSRP_SO_DTM). In the outer level there's no more SP/QSRP but only dt, so it would be:
WHERE (SO_DTM=MAX_SO_DTM AND QSRP_SO_DTM = MAX_SO_DTM)