SQL WITH not working - sql

I have created a query but it is not working. Can anyone explain this to me? Thanks!
WITH rows AS
(
SELECT *, ROW_NUMBER() OVER (ORDER BY dtDeliveryDate) AS rn
FROM TCheckRecipient
)
select avg(avarage) from(
SELECT TCheck.iCheckId, AVG(DATEDIFF(minute, mc.dtDeliveryDate, mp.dtDeliveryDate)) as avarage
FROM rows mc
left join TCheck on TCheck.iCheckId = mc.iCheckId
JOIN rows mp
ON mc.rn = mp.rn - 1
group by TCheck.iCheckId
)
When I was doing
WITH rows AS
(
SELECT *, ROW_NUMBER() OVER (ORDER BY dtDeliveryDate) AS rn
FROM TCheckRecipient
)
SELECT TCheck.iCheckId, AVG(DATEDIFF(minute, mc.dtDeliveryDate, mp.dtDeliveryDate)) as avarage
FROM rows mc
left join TCheck on TCheck.iCheckId = mc.iCheckId
JOIN rows mp
ON mc.rn = mp.rn - 1
group by TCheck.iCheckId
It works well.
But when I try to make the average of those returns, and I can not,
I'd be happy if someone would answer me how to do it thanks

I'll put an answer in so that my comment has more clarity. You might just need to alias the inner query.
WITH rows AS
(
SELECT *, ROW_NUMBER() OVER (ORDER BY dtDeliveryDate) AS rn
FROM TCheckRecipient
)
select avg(avarage) from(
SELECT TCheck.iCheckId, AVG(DATEDIFF(minute, mc.dtDeliveryDate, mp.dtDeliveryDate)) as avarage
FROM rows mc
left join TCheck on TCheck.iCheckId = mc.iCheckId
JOIN rows mp
ON mc.rn = mp.rn - 1
group by TCheck.iCheckId
) A

Related

Left join tables in sqlite ordered by desc limit

I want to left join two tables in sqlite. Short summary:
I have a table named "_Menu", one of the fields in this table is named "menu_id" with unique numbers.
Another table is called "_Approvals". This table has a history of which items has been "approved" or "unapproved". This table also has a field named "menu_id".
I want to get the lowest row (if there is any) from "_Approvals" for a given menu_id and join the two tables.
What I have so far is:
SELECT m.menu_id, m.p_id AS parent_id, m.name, m.url, a.status, a.auth
FROM _Menu AS m
LEFT JOIN (
SELECT * FROM _Approvals ORDER BY _Approvals.approval_id DESC LIMIT 1) as a
ON a.menu_id = m.menu_id
GROUP BY m.menu_id
ORDER BY m.menu_id
My problem is only the absolute last row in "_Approvals" gets joined. I.e I only know the status of the last item approved/unapproved.
Any help is greatly appreciated!
You want the lowest row (if there is any) from "_Approvals" for a given menu_id and not the the lowest row from "_Approvals" which is what your code does.
One way to do what you need is by using NOT EXISTS in the subquery that you join:
SELECT m.menu_id, m.p_id AS parent_id, m.name, m.url, a.status, a.auth
FROM _Menu AS m
LEFT JOIN (
SELECT * FROM _Approvals t
WHERE NOT EXISTS (
SELECT 1 FROM _Approvals
WHERE menu_id = t.menu_id AND approval_id > t.approval_id
)
) AS a
ON a.menu_id = m.menu_id
GROUP BY m.menu_id
ORDER BY m.menu_id
Another way with a CTE:
WITH cte AS (
SELECT t.* FROM _Approvals t
INNER JOIN (
SELECT menu_id, MAX(approval_id)
FROM _Approvals
GROUP BY menu_id
) g
ON g.menu_id = t.menu_id
)
SELECT m.menu_id, m.p_id AS parent_id, m.name, m.url, a.status, a.auth
FROM _Menu AS m LEFT JOIN cte AS a
ON a.menu_id = m.menu_id
GROUP BY m.menu_id
ORDER BY m.menu_id
Or with window function ROW_NUMBER() if your version of SQLite is 3.25.0+:
WITH cte AS (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY menu_id ORDER BY approval_id DESC) rn
FROM _Approvals
)
SELECT m.menu_id, m.p_id AS parent_id, m.name, m.url, a.status, a.auth
FROM _Menu AS m LEFT JOIN (
SELECT * FROM cte
WHERE rn = 1
) AS a
ON a.menu_id = m.menu_id
GROUP BY m.menu_id
ORDER BY m.menu_id
I would recommend writing this using row_number():
SELECT m.menu_id, m.p_id AS parent_id, m.name, m.url,
a.status, a.auth
FROM _Menu m LEFT JOIN
(SELECT a.*,
ROW_NUMBER() OVER (PARTITION BY a.menu_id ORDER BY a.approval_id DESC) as seqnum
FROM _Approvals a
) a
ON a.menu_id = m.menu_id AND a.seqnum = 1
ORDER BY m.menu_id;
No aggregation should be needed for the query, assuming that menu_id is the primary key in _Menu.
If you are using an old version of SQLite that doesn't support window functions, then there are several options. Probably the simplest is:
SELECT m.menu_id, m.p_id AS parent_id, m.name, m.url,
a.status, a.auth
FROM _Menu m LEFT JOIN
_Approvals a
ON a.menu_id = m.menu_id LEFT JOIN
(SELECT a.menu_id, MAX(a.approval_id) as max_approval_id
FROM _Approvals a
GROUP BY a.menu_id
) aa
ON aa.menu_id = a.menu_id AND
aa.max_approval_id = a.approval_id
ORDER BY m.menu_id;

Get Min date as condition

I have a table that contains invoices for all phone numbers, and each number has several invoices, I want to display only the first invoice for precise number but i don't really know how get only first invoice , this is my query
SELECT
b.contrno
a.AR_INVDATE
FROM P_STG_TABS.IVM_INVOICE_RECORD a
INNER JOIN P_EDW_TMP.invoice b
ON b.contrno=a.contrno
WHERE a.AR_INVDATE< (SELECT AR_INVDATE FROM P_STG_TABS.IVM_INVOICE_RECORD WHERE contrno=b.contrno )
Teradata supports a QUALIFY clause to filter the result of an OLAP-function (similar to HAVING after GROUP BY), which greatly simplifies Tim Biegeleisens's answer:
SELECT *
FROM P_STG_TABS.IVM_INVOICE_RECORD a
INNER JOIN P_EDW_TMP.invoice b
ON b.contrno = a.contrno
QUALIFY
ROW_NUMBER()
OVER (PARTITION BY b.contrno
ORDER BY a.AR_INVDATE) = 1
Additionally you can apply the ROW_NUMBER before the join (might be more efficient depending on additional conditions):
SELECT *
FROM
( SELECT *
FROM P_STG_TABS.IVM_INVOICE_RECORD a
QUALIFY
ROW_NUMBER()
OVER (PARTITION BY b.contrno
ORDER BY a.AR_INVDATE) = 1
) AS a
INNER JOIN P_EDW_TMP.invoice b
ON b.contrno = a.contrno
Use ROW_NUMBER():
SELECT
t.contrno,
t.AR_INVDATE
FROM
(
SELECT
b.contrno,
a.AR_INVDATE,
ROW_NUMBER() OVER (PARTITION BY b.contrno ORDER BY a.AR_INVDATE) rn
FROM P_STG_TABS.IVM_INVOICE_RECORD a
INNER JOIN P_EDW_TMP.invoice b
ON b.contrno = a.contrno
) t
WHERE t.rn = 1;
If you are worried about ties, and you want to display all ties, then you can replace ROW_NUMBER with either RANK or DENSE_RANK.
If I correctly understand, then one way is to use group by with min(a.AR_INVDATE):
SELECT
b.contrno,
min(a.AR_INVDATE)
FROM P_STG_TABS.IVM_INVOICE_RECORD a
INNER JOIN P_EDW_TMP.invoice b
ON b.contrno=a.contrno
group by b.contrno

I have created a query but it is not working

WITH rows AS
(
SELECT
*, ROW_NUMBER() OVER (ORDER BY dtDeliveryDate) AS rn
FROM
TCheckRecipient
)
SELECT
AVG(avarage)
FROM
(SELECT
TCheck.iCheckId,
AVG(DATEDIFF(minute, mc.dtDeliveryDate, mp.dtDeliveryDate)) AS average
FROM
rows mc
LEFT JOIN
TCheck ON TCheck.iCheckId = mc.iCheckId
JOIN
rows mp ON mc.rn = mp.rn - 1
GROUP BY
TCheck.iCheckId)
You have Typo error in AVG(avarage) , it should be average.
And also, remember to assign alias on your subquery.
WITH rows AS
(
SELECT
*, ROW_NUMBER() OVER (ORDER BY dtDeliveryDate) AS rn
FROM
TCheckRecipient
)
SELECT
AVG(avarage)
FROM
(SELECT
TCheck.iCheckId,
AVG(DATEDIFF(minute, mc.dtDeliveryDate, mp.dtDeliveryDate)) AS average
FROM
rows mc
LEFT JOIN
TCheck ON TCheck.iCheckId = mc.iCheckId
JOIN
rows mp ON mc.rn = mp.rn - 1
GROUP BY
TCheck.iCheckId) as A

Highest Count with a group

I'm having an absolute brain fade
SELECT p.ProductCategory, f.ProductSubCategory, COUNT(*) AS Cnt
FROM Sales f
JOIN Products p ON f.ProductSubCategory = p.ProductSubCategory
GROUP BY p.ProductCategory, f.ProductSubCategory
ORDER BY 1,3 DESC
This shows me the count for each ProductSubCategory, I would like to see only the highest ProductSubCategory per ProductCategory.
I wish to see (I don't care about the Count value)
There are a couple of different ways to do this. One involves joining the results back to themselves and using the max aggregate. But since you are using SQL Server, you can use ROW_NUMBER to achieve the same result:
with cte as (
select p.productcategory, p.ProductSubCategory, COUNT(*) cnt,
ROW_NUMBER() over (partition by p.productcategory order by count(*) desc) rn
from products p
join sales s on p.ProductSubCategory = s.ProductSubCategory
group by p.productcategory, p.ProductSubCategory
)
select *
from cte
where rn = 1
You already got the answer, Please see the following code to. It may help you.
SELECT p.ProductCategory,
f.ProductSubCategory,
COUNT(*) AS Cnt
FROM Sales f
JOIN Products p ON f.ProductSubCategory = p.ProductSubCategory
JOIN (
SELECT p.ProductCategory,
f.ProductSubCategory,
ROW_NUMBER() OVER ( PARTITION BY p.ProductCategory,
f.ProductSubCategory
ORDER BY COUNT(*) DESC) [Row]
FROM Sales f
JOIN Products p ON f.ProductSubCategory = p.ProductSubCategory) Lu
ON P.ProductCategory = Lu.ProductCategory
AND f.ProductSubCategory = Lu.ProductSubCategory
WHERE Lu.Row = 1
GROUP By p.ProductCategory,
f.ProductSubCategory

SQL: improving join efficiency

If I turn this sub-query which selects sales persons and their highest price paid for any item they sell:
select *,
(select top 1 highestProductPrice
from orders o
where o.salespersonid = s.id
order by highestProductPrice desc ) as highestProductPrice
from salespersons s
in to this join in order to improve efficiency:
select *, highestProductPrice
from salespersons s join (
select salespersonid, highestProductPrice, row_number(
partition by salespersonid
order by salespersonid, highestProductPrice) as rank
from orders ) o on s.id = o.salespersonid
It still touches every order record (it enumerates the entire table before filtering by salespersonid it seems.) However you cannot do this:
select *, highestProductPrice
from salespersons s join (
select salespersonid, highestProductPrice, row_number(
partition by salespersonid
order by salespersonid, highestProductPrice) as rank
from orders
where orders.salepersonid = s.id) o on s.id = o.salespersonid
The where clause in the join causes a `multi-part identifier "s.id" could not be bound.
Is there any way to join the top 1 out of each order group with a join but without touching each record in orders?
Try
SELECT
S.*,
T.HighestProductPrice
FROM
SalesPersons S
CROSS APPLY
(
SELECT TOP 1 O.HighestProductPrice
FROM Orders O
WHERE O.SalesPersonid = S.Id
ORDER BY O.SalesPersonid, O.HighestProductPrice DESC
) T
would
select s.*, max(highestProductPrice)
from salespersons s
join orders o on o.salespersonid = s.id
group by s.*
or
select s.*, highestProductPrice
from salespersons s join (select salepersonid,
max(highestProductPrice) as highestProductPrice
from orders o) as o on o.salespersonid = s.id
work?