How to solve ambiguous column name in SQL server? - sql

I run the below SQL query and get this error: Errors: Ambiguous column name 'EmailAddress'.
Have tried to use select R.EmailAddress..., but it got me the same error.
Without the Join the query works well.
what am I missing?
select EmailAddress, [Order Number], order_date, rank,
ROW_NUMBER() OVER (PARTITION BY order_date, EmailAddress ORDER BY order_date DESC) AS rankDate,
R.firstname as 'FirstName',R.lastname as 'LastName', 'IL' as 'Locale'
from(
select
O.FirstName, O.LastName, O.email as 'EmailAddress',
O.order_number as 'Order Number',O.order_date,
ROW_NUMBER() OVER (PARTITION BY O.email ORDER BY O.order_date DESC) AS rank,
O.order_number as 'Order Number Compare'
from [TEST ORDER] O
where O.order_date>='12/27/2020' and O.email is not null
) as R
join [All Blend Subscribers] as ABS
on R.EmailAddress = ABS.emailAddress

Because of your need to tell SQL server what EmailAddress want to get from tables on SELECT part, there are two kind of EmailAddress from your query.
select R.EmailAddress, [Order Number], order_date, rank,
ROW_NUMBER() OVER (PARTITION BY order_date, R.EmailAddress ORDER BY order_date DESC) AS rankDate,
R.firstname as 'FirstName',R.lastname as 'LastName', 'IL' as 'Locale'
from(
select
O.FirstName, O.LastName, O.email as 'EmailAddress',
O.order_number as 'Order Number',O.order_date,
ROW_NUMBER() OVER (PARTITION BY O.email ORDER BY O.order_date DESC) AS rank,
O.order_number as 'Order Number Compare'
from [TEST ORDER] O
where O.order_date>='12/27/2020' and O.email is not null
) as R
join [All Blend Subscribers] as ABS
on R.EmailAddress = ABS.emailAddress
I would get columns by an alias clearly because it can avoid ambiguous error.

Related

Psql : Get Min, Max and Count records for each partner' invoice, and last payment

I have a table invoice like this :
id, partner_id, number, invoice_date
And a Payment Table like this:
id, payment_date, partner_id
I want to get min and max for both number & invoice_date, and count invoices, and last payment for each partner, something like this :
partner_id, min number, min date, max number, max date, count, last_pay
1, INV-2017-003, 02-01-2017, INV-2020-010, 01-01-2020, 142, 02-12-2019
5, INV-2019-124, 05-03-2019, INV-2020-005, 01-01-2020, 150, 01-01-2020
....
You can join those three tables including partners and grouping by parners' id column along with related aggregations :
select pr.id, min(invoice_date), max(invoice_date), count(*), max(payment_date) as last_pay
from partners pr
left join invoices i on i.partner_id = pr.id
left join payments p on p.partner_id = pr.id
group by pr.id
Update : You can use min() over (), max() over () and row_number() analytic functions to get the desired code depending on max and min dates :
select *
from
(
select pr.id,
min(invoice_date) over (partition by pr.id order by invoice_date) as min_invoice_date,
max(invoice_date) over (partition by pr.id order by invoice_date desc) as max_invoice_date,
max(code) over (partition by pr.id order by invoice_date desc) as max_code,
min(code) over (partition by pr.id order by invoice_date) as min_code,
count(*) over (partition by pr.id) as cnt,
max(payment_date) over (partition by pr.id) as last_pay,
row_number() over (partition by pr.id order by invoice_date desc) as rn
from partners pr
left join invoices i on i.partner_id = pr.id
left join payments p on p.partner_id = pr.id
) q
where rn = 1
Why isn't this simple aggregation?
select i.partner_id,
min(i.number) as min_number,
min(i.invoice_date) as min_invoice_date,
max(i.number) as min_number,
max(i.invoice_date) as min_invoice_date,
count(distinct i.invoice_id) as num_invoices,
max(p.payment_date) as max_payment_date
from invoices i left join
payments p
on p.invoice_id = i.invoice_id
group by i.partner_id;
If you want the number on the earliest invoice (and min() doesn't work), then you can do this with a "first" aggregation function. Unfortunately, Postgres doesn't directly support one. But it does through array functions:
select i.partner_id,
(array_agg(i.number order by i.invoice_date asc))[1] as min_number,
min(i.invoice_date) as min_invoice_date,
(array_agg(i.number order by i.invoice_date desc))[1] as min_number,
max(i.invoice_date) as min_invoice_date,
count(distinct i.invoice_id) as num_invoices,
max(p.payment_date) as max_payment_date
from invoices i left join
payments p
on p.partner_id = i.partner_id
group by i.partner_id;
This is similar to #BarbarosÖzhan, but calculates the min/max before the join (if you got multiple rows per partner for both invoices and payments the COUNT will be wrong otherwise). Additionally there's only a single PARTTION/ORDER which should result in a more efficient plan.
SELECT i.*, p.last_pay
FROM
( -- 1st row has all the min values = filtered using row_number
SELECT
partner_id
,number AS min_code
,invoice_date AS min_invoice_date
-- value from row with max date
,Last_Value(number)
Over (PARTITION BY partner_id
ORDER BY invoice_date
ROWS BETWEEN Unbounded Preceding AND Unbounded Following) AS max_code
,Last_Value(invoice_date)
Over (PARTITION BY partner_id
ORDER BY invoice_date
ROWS BETWEEN Unbounded Preceding AND Unbounded Following) AS max_invoice_date
,Count(*)
Over (PARTITION BY partner_id) AS Cnt
,Row_Number()
Over (PARTITION BY partner_id ORDER BY invoice_date) AS rn
FROM invoices
) AS i
LEFT JOIN
( -- max payment date per partner
SELECT partner_id, Max(payment_date) AS last_pay
FROM payments
GROUP BY partner_id
) AS p
ON p.partner_id = i.partner_id
WHERE i.rn = 1

How to get current and last order from Northwind db using Correlated queries

Using the northwind db on mssql, i am trying to retrieve the customer's last two order dates and calculate the time between the two orders.
So something like
select c.CompanyName, o.OrderDate, o2.OrderDate,
DateDiff(d, o.OrderDate, o2.OrderDate) as TimeElapsed
unfortunately not sure how to construct it from there.
i have something like this but it's still wrong.
select c.CompanyName, o.OrderDate, o2.OrderDate,
DateDiff(d, o.OrderDate, o2.OrderDate) as TimeElapsed
from Orders o
INNER JOIN Customers ON c.CustomerID = o.CustomerID
INNER JOIN (
select OrderID, OrderDate
FROM Orders
order by OrderDate
OFFSET 1 ROWS
FETCH NEXT 1 ROW ONLY
) as o2 ON o.OrderID = o2.OrderID;
can anyone assist.
Thank you
Northwind has been obsolete for years; even AdventureWorks has been replaced. The following uses the latter but you should be able to easily translate it to your schema. Two different approaches. The last 2 select statements are used to verify the results. Notice that customer 30099 has only one order.
set nocount on;
with cte as (select SalesOrderID, OrderDate, CustomerID, row_number () over (partition by CustomerID order by OrderDate desc) as rn
from Sales.SalesOrderHeader)
select top 10 * from cte
where rn <= 2
order by CustomerID, rn;
with cte as (select SalesOrderID, OrderDate, CustomerID, row_number () over (partition by CustomerID order by OrderDate desc) as rn
from Sales.SalesOrderHeader)
select cte.CustomerID, min(cte.OrderDate) as mindate, max(cte.OrderDate),
case when min(cte.OrderDate) = max(cte.OrderDate) then cast(null as int)
else datediff(day, min(cte.OrderDate), max(cte.OrderDate)) end as dif
from cte
where rn <= 2
group by cte.CustomerID
order by CustomerID;
with cte as (select SalesOrderID, OrderDate, CustomerID, row_number () over (partition by CustomerID order by OrderDate desc) as rn
from Sales.SalesOrderHeader)
select cte.CustomerID, minr.OrderDate as mindate, cte.OrderDate as maxdate,
datediff(day, minr.OrderDate, cte.OrderDate) as dif
from cte left join cte as minr on cte.CustomerID = minr.CustomerID and minr.rn = 2
where cte.rn = 1
order by cte.CustomerID;
select top 2 CustomerID, OrderDate from Sales.SalesOrderHeader where CustomerID = 30118 order by OrderDate desc;
select top 2 CustomerID, OrderDate from Sales.SalesOrderHeader where CustomerID = 30099 order by OrderDate desc;

oracle window functions

Could someone help me out with this query:
SELECT SUM(summa), name,
TO_CHAR(invoice_date, 'YYYY/mm')
OVER (PARTITON EXTRACT(MONTH FROM i.invoice_date, c.name)
FROM invoice i, customer c
WHERE i.customer_id = c.id
AND months_between(sysdate, invoice_date) = 3
AND rownum < 11 GROUP BY invoice_date, name
ORDER BY SUM(SUMMA) DESC;
Supposed to get the first ten rows from last three months, grouped by month and ordered by sum.
Thanks.
First, use proper explicit join syntax. Second, you need row_number():
SELECT t.*
FROM (SELECT SUM(summa) as sumsumma, name,
TO_CHAR(invoice_date, 'YYYY/mm') as yyyymm,
ROW_NUMBER() OVER (PARTITION BY TO_CHAR(invoice_date, 'YYYY/mm')
ORDER BY SUM(summa) DESC
) as seqnum
FROM invoice i JOIN
customer c
ON i.customer_id = c.id
WHERE months_between(sysdate, invoice_date) = 3
GROUP BY invoice_date, name
) t
WHERE seqnum <= 10
ORDER BY sumsumma DESC;

How to pull the whole row which has the latest date in SQL?

I’m trying to select the pair of product – distribution center attached with the most recent order (based on order date). For one order I can have multiple products, but the whole order will be shipped from one specific distribution center.
How do I select the specific product-distribution center attached with the latest order?
My structure is basically like this:
data.orderdetail table has ordernum, orderdate, distributioncenter
I tried to pull like this, but it doesn’t give me the desired result. I’m using sql server 2008:
SELECT DISTINCT y.OrderNum, y.Product, y.DistributionCenter
, CAST(y.OrderDate AS DATE) AS Orderdate
FROM (SELECT OrderNum, MAX(CAST(Orderdate AS date)) AS orderdate
FROM data.OrderDetail
GROUP BY OrderNum) AS x
INNER JOIN data.OrderDetail AS y
ON y.OrderNum = x.OrderNum
It looks as if you need one more clause in your join Condition
You've got
ON y.OrderNum = x.OrderNum
Which will return all the orders that match the Order number in the subquery
But you'll need
ON y.OrderNum = x.OrderNum
AND y.OrderDate = x.orderdate
Which will return all the orders that match the Order number in the subquery and the maximum date for that order number
SELECT DISTINCT
y.OrderNum,
y.Product,
y.DistributionCenter,
CAST(y.OrderDate AS DATE) AS Orderdate
FROM (
SELECT
OrderNum,
MAX(CAST(Orderdate AS date)) AS orderdate
FROM data.OrderDetail
GROUP BY OrderNum
) AS x
INNER JOIN
data.OrderDetail AS y
ON y.OrderNum = x.OrderNum
AND y.OrderDate = x.orderdate
I believe what you are looking for is row_number. This will partition your result set by OrderNum then rank the sets by the OrderDate. You can then filter off the extra rows in another where clause.
select result.*,
CAST(result.OrderDate as date) as Orderdate,
from (
select y.*,
row_number() over (
partition by y.OrderNum order by CAST(y.OrderDate as date) desc
) rank_
from (
select OrderNum,
MAX(CAST(Orderdate as date)) as orderdate
from data.OrderDetail
group by OrderNum
) as x
inner join data.OrderDetail as y on y.OrderNum = x.OrderNum
) result
where result.rank_ = 1;
select * from
(
SELECT OrderNum, Product, DistributionCenter, OrderDate
, ROW_NUMBER() over (partition by OrderNum order by OrderDate desc) as rownum
FROM OrderDetail
) as xxx
where xxx.rownum = 1
ROW_NUMBER (Transact-SQL)
Try this.
; WITH CTE1
AS (
SELECT
od.OrderNum
, od.Product
, od.DistributionCenter
, CAST(od.OrderDate AS DATE) AS OrderDate
, RowNumber = ROW_NUMBER() OVER (PARTITION BY od.Product, od.DistributionCenter ORDER BY CAST(od.OrderDate AS DATE) DESC)
FROM data.OrderDetail od
)
SELECT
OrderNum
, Product
, DistributionCenter
, OrderDate
FROM CTE1
WHERE RowNumber = 1

MySQL: Returning multiple columns from an in-line subquery

I'm creating an SQL statement that will return a month by month summary on sales.
The summary will list some simple columns for the date, total number of sales and the total value of sales.
However, in addition to these columns, i'd like to include 3 more that will list the months best customer by amount spent. For these columns, I need some kind of inline subquery that can return their ID, Name and the Amount they spent.
My current effort uses an inline SELECT statement, however, from my knowledge on how to implement these, you can only return one column and row per in-line statement.
To get around this with my scenario, I can of course create 3 separate in-line statements, however, besides this seeming impractical, it increases the query time more that necessary.
SELECT
DATE_FORMAT(OrderDate,'%M %Y') AS OrderMonth,
COUNT(OrderID) AS TotalOrders,
SUM(OrderTotal) AS TotalAmount,
(SELECT SUM(OrderTotal) FROM Orders WHERE DATE_FORMAT(OrderDate,'%M %Y') = OrderMonth GROUP BY OrderCustomerFK ORDER BY SUM(OrderTotal) DESC LIMIT 1) AS TotalCustomerAmount,
(SELECT OrderCustomerFK FROM Orders WHERE DATE_FORMAT(OrderDate,'%M %Y') = OrderMonth GROUP BY OrderCustomerFK ORDER BY SUM(OrderTotal) DESC LIMIT 1) AS CustomerID,
(SELECT CustomerName FROM Orders INNER JOIN Customers ON OrderCustomerFK = CustomerID WHERE DATE_FORMAT(OrderDate,'%M %Y') = OrderMonth GROUP BY OrderCustomerFK ORDER BY SUM(OrderTotal) DESC LIMIT 1) AS CustomerName
FROM Orders
GROUP BY DATE_FORMAT(OrderDate,'%m%y')
ORDER BY DATE_FORMAT(OrderDate,'%y%m') DESC
How can i better structure this query?
FULL ANSWER
After some tweaking of Dave Barkers solution, I have a final version for anyone in the future looking for help.
The solution by Dave Barker worked perfectly with the customer details, however, it made the simpler Total Sales and Total Sale Amount columns get some crazy figures.
SELECT
Y.OrderMonth, Y.TotalOrders, Y.TotalAmount,
Z.OrdCustFK, Z.CustCompany, Z.CustOrdTotal, Z.CustSalesTotal
FROM
(SELECT
OrdDate,
DATE_FORMAT(OrdDate,'%M %Y') AS OrderMonth,
COUNT(OrderID) AS TotalOrders,
SUM(OrdGrandTotal) AS TotalAmount
FROM Orders
WHERE OrdConfirmed = 1
GROUP BY DATE_FORMAT(OrdDate,'%m%y')
ORDER BY DATE_FORMAT(OrdDate,'%Y%m') DESC)
Y INNER JOIN
(SELECT
DATE_FORMAT(OrdDate,'%M %Y') AS CustMonth,
OrdCustFK,
CustCompany,
COUNT(OrderID) AS CustOrdTotal,
SUM(OrdGrandTotal) AS CustSalesTotal
FROM Orders INNER JOIN CustomerDetails ON OrdCustFK = CustomerID
WHERE OrdConfirmed = 1
GROUP BY DATE_FORMAT(OrdDate,'%m%y'), OrdCustFK
ORDER BY SUM(OrdGrandTotal) DESC)
Z ON Z.CustMonth = Y.OrderMonth
GROUP BY DATE_FORMAT(OrdDate,'%Y%m')
ORDER BY DATE_FORMAT(OrdDate,'%Y%m') DESC
Move the inline SQL to be a inner join query. So you'd have something like...
SELECT DATE_FORMAT(OrderDate,'%M %Y') AS OrderMonth, COUNT(OrderID) AS TotalOrders, SUM(OrderTotal) AS TotalAmount, Z.OrderCustomerFK, Z.CustomerName, z.OrderTotal as CustomerTotal
FROM Orders
INNER JOIN (SELECT DATE_FORMAT(OrderDate,'%M %Y') as Mon, OrderCustomerFK, CustomerName, SUM(OrderTotal) as OrderTotal
FROM Orders
GROUP BY DATE_FORMAT(OrderDate,'%M %Y'), OrderCustomerFK, CustomerName ORDER BY SUM(OrderTotal) DESC LIMIT 1) Z
ON Z.Mon = DATE_FORMAT(OrderDate,'%M %Y')
GROUP BY DATE_FORMAT(OrderDate,'%m%y'), Z.OrderCustomerFK, Z.CustomerName
ORDER BY DATE_FORMAT(OrderDate,'%y%m') DESC
You can also do something like:
SELECT
a.`y`,
( SELECT #c:=NULL ) AS `temp`,
( SELECT #d:=NULL ) AS `temp`,
( SELECT
CONCAT(#c:=b.`c`, #d:=b.`d`)
FROM `b`
ORDER BY b.`uid`
LIMIT 1 ) AS `temp`,
#c as c,
#d as d
FROM `a`
Give this a shot:
SELECT CONCAT(o.order_month, ' ', o.order_year),
o.total_orders,
o.total_amount,
x.sum_order_total,
x.ordercustomerfk,
x.customername
FROM (SELECT MONTH(t.orderdate) AS order_month,
YEAR(t.orderdate) AS order_year
COUNT(t.orderid) AS total_orders,
SUM(t.ordertotal) AS total_amount
FROM ORDERS t
GROUP BY MONTH(t.orderdate), YEAR(t.orderdate)) o
JOIN (SELECT MONTH(t.orderdate) AS ordermonth,
YEAR(t.orderdate) AS orderyear
SUM(t.ordertotal) 'sum_order_total',
t.ordercustomerfk,
c.customername
FROM ORDERS t
JOIN CUSTOMERS c ON c.customerid = o.ordercustomerfk
GROUP BY t.ordercustomerfk, MONTH(t.orderdate), YEAR(t.orderdate)) x ON x.order_month = o.order_month
AND x.order_year = o.order_year
ORDER BY o.order_year DESC, o.order_month DESC