SQL add STUFF function into this query - sql

I have the following query
SELECT TOP 1000
o.BuyerEMail,
COUNT(*) HowMany,
o.Name, o2.OrderID
FROM
Orders o
JOIN
(SELECT
BuyerEmail, MAX(OrderDate) Latest
FROM Orders
GROUP BY BuyerEmail) l ON o.BuyerEmail = l.BuyerEmail
JOIN
Orders o2 ON l.BuyerEmail = o2.BuyerEmail
AND l.OrderDate = o2.OrderDate
WHERE
Pay != 'PayPal'
GROUP BY
o.BuyerEmail, o.Name, l.Latest
ORDER BY
It's just producing a report about customers and how many orders they have with us and the latest order.
What I want to add is a list of the products of their last order which are in lines table.
Lines table is linked to order table by OrderID.
I was looking for something like:
JOIN
(SELECT
OrderID,
STUFF((SELECT ', ' + li.Code
FROM tblLines li
WHERE li.OrderID = o2.OrderID
FOR XML PATH ('')), 1, 1, '') AS [Codes]
GROUP BY
OrderID, Code
So the final table displays as
BuyerEmail | HowMany | Name | Latest | Codes
---------------------------------------------
Bob#bob | 4 | bob | 10000 | 123,10,201231

As you posted the query from another question (SQL most recent order? MS SQL), I will use my answer as it is cleaner than the above query:
SELECT o.*
, OrderID as LastOrderID
FROM (
SELECT BuyerEMail
, Name
, COUNT(*) as TotalOrders
FROM Orders
WHERE Pay != 'PayPal'
GROUP BY BuyerEmail, Name
) o
CROSS APPLY (
SELECT TOP 1 OrderID, OrderDate
FROM Orders s
WHERE s.BuyerEmail = o.BuyerEmail
ORDER BY OrderDate DESC
) ca
You posted a good example, it wasn't complete thou. You would need the following xmlpath query:
SELECT OrderID
, Codes
FROM tblLines r1
CROSS APPLY (
SELECT
STUFF((SELECT ',' + CAST(Code AS NVARCHAR)
FROM tblLines r2
WHERE r2.OrderID = r1.OrderID
GROUP BY OrderID, Code
ORDER BY Code
FOR XML PATH (''), TYPE)
.value('.', 'varchar(max)')
, 1, 1, '')) OrderLines(Codes)
GROUP BY OrderID, OrderList
Add it to the previous statement with a simple join:
SELECT o.BuyerEMail
,o.Name
,o.TotalOrders
, OrderID as LastOrderID
, c.Codes
FROM (
SELECT BuyerEMail
, Name
, COUNT(*) as TotalOrders
FROM Orders
WHERE Pay != 'PayPal'
GROUP BY BuyerEmail, Name
) o
CROSS APPLY (
SELECT TOP 1 OrderID, OrderDate
FROM Orders s
WHERE s.BuyerEmail = o.BuyerEmail
ORDER BY OrderDate DESC
) ca
INNER JOIN (
SELECT OrderID
, Codes
FROM tblLines r1
CROSS APPLY (
SELECT
STUFF((SELECT ',' + CAST(Code AS NVARCHAR)
FROM tblLines r2
WHERE r2.OrderID = r1.OrderID
GROUP BY OrderID, Code
ORDER BY Code
FOR XML PATH (''), TYPE)
.value('.', 'varchar(max)')
, 1, 1, '')) OrderLines(Codes)
GROUP BY OrderID, OrderList
) c
ON ca.OrderID = c.OrderID

SELECT TOP 1000
o.BuyerEMail,
COUNT(*) HowMany,
o.Name, l.Latest,
STUFF((SELECT ', ' + li.Code
FROM tblLines li
WHERE li.OrderID = o2.OrderID
FOR XML PATH ('')), 1, 1, '') AS [Codes]
FROM
Orders o
JOIN
(SELECT
BuyerEmail, MAX(OrderDate) Latest
FROM Orders
GROUP BY BuyerEmail) l ON o.BuyerEmail = l.BuyerEmail
JOIN
Orders o2 ON l.BuyerEmail = o2.BuyerEmail
AND l.OrderDate = o2.OrderDate
WHERE
Pay != 'PayPal'
GROUP BY
o.BuyerEmail, o.Name, l.Latest
ORDER BY

Related

SQL - How to Group by and then Concatenate joins?

I have the made a join between 2 tables but the issue is that I need to see unique
CustomerId and concatenate Accreditations with comma separated e,i Gold,Silver,Platinum
Here is my SQL script
SELECT TOP (1000)
Customer.CustomerID,
Customer.CustomerName,
Customer_Accreditations.AccreditationNumber
FROM
Customer INNER JOIN
Customer_Accreditations ON Customer.CustomerID =
Customer_Accreditations.CustomerID
My Result with this script is as follows
CustomerID CustomerName AccreditationNumber
1272 Bree Gold
1272 Bree Gold
1272 Bree Gold
4071 Anneke Silver
4071 Anneke Silver
4071 Anneke Platinum
My desired result should be
CustomerID CustomerName AccreditationNumber
1272 Bree Gold,Gold,Gold
4071 Anneke Silver,Silver,Platinum
So far I have only been able to get unique values and concatenate Accreditations
Here is the script:
SELECT CustomerID, displayname =
STUFF((SELECT DISTINCT ',' + [AccreditationNumber]
FROM Customer_Accreditations b
WHERE b.CustomerID = a.CustomerID
FOR XML PATH('')), 1, 2, '')
FROM [DATABASE_NAME].[dbo].[Customer_Accreditations] a
GROUP BY CustomerID
This returns the following results
______________________________
|CustomerId | displayname |
|____________________________|
|1272 | Gold,Gold,Gold|
______________________________
This is great but if only I could join more of Customer tables/
Many thanks!
Try This
SELECT CustomerID,
CustomerName ,
STUFF(SELECT DISTINCT ', ' + AccreditationNumber
FROM <Table> i
WHERE i.CustomerID = o.CustomerID
FOR XML PATH ('')),1,1,'') AS AccreditationNumber
FROM <Table> o
I think you should be using the customers table to get one row per customer. I think this should be doing what you want:
SELECT c.*,
STUFF( (SELECT ',' + [AccreditationNumber]
FROM Customer_Accreditations ca
WHERE ca.CustomerID = c.CustomerID
FOR XML PATH('')
), 1, 2, ''
) as displayname
FROM [DATABASE_NAME].[dbo].[Customer] c;
SELECT a.CustomerID, a.CustomerName, displayname =
STUFF((SELECT DISTINCT ',' + [AccreditationNumber]
FROM Customer_Accreditations b
WHERE b.CustomerID = a.CustomerID
FOR XML PATH('')), 1, 2, '')
FROM [DATABASE_NAME].[dbo].[Customer] a
GROUP BY a.CustomerID, a.CustomerName

How to combine these 2 SQL query results?

1st Query:
Select O.TrainDate, O.RailHead, O.Position as Pos,
O.Iso, C.CustomerName + ' (' + O.Customer + ')' as Customer,
P.ProductName + ' ('+O.Product +')' as Product,
O.Target, O.Docket, o.Gross, o.Tare ,o.Net, o.ConNote, o.Description
from IsoOrders O, Customer C, Product P
where o.Customer = c.Customer
and p.Product = o.Product
and o.Traindate >= '12-14-2016'
and o.Iso = '040'
2nd Query:
select top 1 isodeldocket, product from trans where container = '040'
order by despatchdatetime desc
The last query's result was to be added as the last 2 columns of the 1st query.
Solving the problem in your query
You can do it like this:
select
O.TrainDate, O.RailHead, O.Position as Pos, O.Iso,
C.CustomerName + ' (' + O.Customer + ')' as Customer,
P.ProductName + ' ('+ O.Product +')' as Product,
O.Target, O.Docket, O.Gross, O.Tare, O.Net, O.ConNote, O.Description,
-- Added these columns
T.isodeldocket,
T.product
from
IsoOrders O,
Customer C,
Product P,
-- Added this derived table
(select top 1 isodeldocket, product
from trans
where container = '040'
order by despatchdatetime desc) T
where O.Customer = C.Customer and P.Product = O.Product
and O.Traindate >= '12-14-2016'
and O.Iso = '040'
Improving the query by using ANSI JOIN syntax
While you're refactoring this query, why not move to ANSI JOIN, which greatly simplifies readability and clearly shows the intent / difference between (INNER) JOIN and CROSS JOIN:
select
O.TrainDate, O.RailHead, O.Position as Pos, O.Iso,
C.CustomerName + ' (' + O.Customer + ')' as Customer,
P.ProductName + ' ('+ O.Product +')' as Product,
O.Target, O.Docket, O.Gross, O.Tare, O.Net, O.ConNote, O.Description,
T.isodeldocket,
T.product
from IsoOrders O
join Customer C on O.Customer = C.Customer
join Product P on P.Product = O.Product
-- CROSS JOIN more explicitly reveals your intention than a comma-separated table list
cross join (
select top 1 isodeldocket, product
from trans
where container = '040'
order by despatchdatetime desc
) T
where O.Traindate >= '12-14-2016'
and O.Iso = '040'
Correlating the "outer" O.Iso with the "inner" trans.container value
From your comments, I take that you want to take this one step further and avoid duplicating the '040' "parameter". This can be done in SQL Server using APPLY:
select
O.TrainDate, O.RailHead, O.Position as Pos, O.Iso,
C.CustomerName + ' (' + O.Customer + ')' as Customer,
P.ProductName + ' ('+ O.Product +')' as Product,
O.Target, O.Docket, O.Gross, O.Tare, O.Net, O.ConNote, O.Description,
T.isodeldocket,
T.product
from IsoOrders O
join Customer C on O.Customer = C.Customer
join Product P on P.Product = O.Product
-- Use CROSS APPLY rather than CROSS JOIN
cross apply (
select top 1 isodeldocket, product
from trans
where container = O.Iso -- Now, you can access "outer" columns
order by despatchdatetime desc
) T
where O.Traindate >= '12-14-2016'
and O.Iso = '040'

group by function with complicated SELECT

Hi
I have this Statement that select a sum of quantity ans Amounts of products from a big DataBase
SELECT
(SELECT Name FROM AD_Org WHERE AD_Org_ID = 1000001
) AS Org,
(SELECT bp.Name FROM C_BPartner bp WHERE bp.C_BPARTNER_ID = 0
) AS Selected_Vendor,
(SELECT MAX(bp.Name)
FROM C_BPartner bp
WHERE EXISTS
(SELECT 1
FROM M_Product_PO po
WHERE bp.C_BPARTNER_ID =po.C_BPARTNER_ID
AND po.M_PRODUCT_ID = p.M_PRODUCT_ID
AND po.ISCURRENTVENDOR ='Y'
AND AD_Org_ID = 1000001
)
) AS Vendor,
p.Value AS Value_Product,
p.Name AS Name_Product,
COALESCE( SUM(ol.QTYORDERED) , 0) AS qty_bought ,
COALESCE( SUM(ol.LINENETAMT) , 0) AS Amount_bought ,
COALESCE( SUM(ol2.QTYORDERED) , 0) AS qty_sales ,
COALESCE( SUM(ol2.LINENETAMT) , 0) AS Amount_sales,
bomOffQtyOnHand(p.M_PRODUCT_ID,
(SELECT NVL(M_WAREHOUSE_ID,0) FROM AD_OrgInfo WHERE AD_Org_ID = 1000001
), NULL) AS STOCK,
(SELECT Name FROM M_PRODUCT_CATEGORY pc WHERE pc.M_PRODUCT_CATEGORY_ID =0
) AS Product_Category
FROM M_Product p
LEFT OUTER JOIN C_OrderLine ol
ON (p.m_product_id = ol.m_product_id)
INNER JOIN C_Order o
....
....
WHERE (p.M_PRODUCT_CATEGORY_ID =0
....
....
)
ORDER BY p.value,
p.Nam
this statement give me always group function error
ORA-00937: not a single-group group function
when i Put this lines to fix it it give another group by error
GROUP BY SUM(ol.QTYORDERED) ,
SUM(ol.LINENETAMT),
SUM(ol2.QTYORDERED),
SUM(ol2.LINENETAMT),
p.Value,
p.name
error
ORA-00934: group function is not allowed here
I think I must put All the selected items in the group by so how can I put this
(SELECT Name FROM AD_Org WHERE AD_Org_ID = 1000001
) AS Org,
or this
(SELECT MAX(bp.Name)
FROM C_BPartner bp
WHERE EXISTS
(SELECT 1
FROM M_Product_PO po
WHERE
....
AND AD_Org_ID = 1000001
)
) AS Vendor,
in the group by or any other method to fix this error
You aggregate with SUM here:
COALESCE( SUM(ol.QTYORDERED) , 0) AS qty_bought ,
COALESCE( SUM(ol.LINENETAMT) , 0) AS Amount_bought ,
COALESCE( SUM(ol2.QTYORDERED) , 0) AS qty_sales ,
COALESCE( SUM(ol2.LINENETAMT) , 0) AS Amount_sales,
So everything else (p.Value, p.Name, p.M_PRODUCT_ID) must be either in the GROUP BY clause or be aggregated, too ( e.g. MIN(p.Value) ).

SQL query select record with Max

I have these records below :
CustomerID | Name | Store | Quantity
1 | Elie | HO | 16
1 | Elie | S1 | 4
I would like to filter customers by taking only their max quantity?
I tried it with Max, but the problem I cannot render all the fields with it. If I add main.store in the first line, the second row shows.
Is there any solution?
Select main.CUSTOMER_ID, main.Name
from
(
Select Name = cus.FIRST_NAME + ' ' + cus.LAST_NAME,
Store = cs.NAME
,Transaction_Number = count(ts.TRANSACTION_SUMMARY_ID)
,cus.CUSTOMER_ID
from TRANSACTION_SUMMARY ts
inner join dbo.CUSTOMER cus
on ts.CUSTOMER_ID = cus.CUSTOMER_ID
inner join dbo.CORPORATE_STORE cs
on ts.CORPORATE_STORE_ID = cs.CORPORATE_STORE_ID
Group by cus.CUSTOMER_ID
,cus.FIRST_NAME
,cus.LAST_NAME
,cs.Name
) as main
Group by CUSTOMER_ID
,main.Name
order by main.CUSTOMER_ID
This is a good use of window functions:
with t as (
Select Name = cus.FIRST_NAME + ' ' + cus.LAST_NAME,
Store = cs.NAME,
Transaction_Number = count(ts.TRANSACTION_SUMMARY_ID) , cus.CUSTOMER_ID
from TRANSACTION_SUMMARY ts
inner join dbo.CUSTOMER cus on ts.CUSTOMER_ID = cus.CUSTOMER_ID
inner join dbo.CORPORATE_STORE cs on ts.CORPORATE_STORE_ID = cs.CORPORATE_STORE_ID
Group by cus.CUSTOMER_ID, cus.FIRST_NAME, cus.LAST_NAME, cs.Name
)
select name, store, Transaction_Number, CUSTOMER_ID
from (select t.*,
row_number() over (partition by customer_id order by transaction_number desc) as seqnum
from t
) t
where seqnum = 1;
You can actually dispense with the subquery. However, using window functions with aggregations looks funny at first:
with t as (
Select Name = cus.FIRST_NAME + ' ' + cus.LAST_NAME,
Store = cs.NAME,
Transaction_Number = count(ts.TRANSACTION_SUMMARY_ID) , cus.CUSTOMER_ID,
row_number() over (partition by cus.CUSTOMER_ID
order by count(ts.TRANSACTION_SUMMARY_ID) desc
) as seqnum
from TRANSACTION_SUMMARY ts
inner join dbo.CUSTOMER cus on ts.CUSTOMER_ID = cus.CUSTOMER_ID
inner join dbo.CORPORATE_STORE cs on ts.CORPORATE_STORE_ID = cs.CORPORATE_STORE_ID
Group by cus.CUSTOMER_ID, cus.FIRST_NAME, cus.LAST_NAME, cs.Name
)
select name, store, Transaction_Number, CUSTOMER_ID
from t
where seqnum = 1;
Please try:
select * From tbl a
where a.Quantity=
(select MAX(b.Quantity) from tbl b where a.CustomerID=b.CustomerID)
what you want is
select customer_id, max( quantity )
from main
group by customer_id
then you can use this to join to itself if you want
select *
from main
, (
select customer_id, max( quantity ) qty
from main
group by customer_id
) m
where main.customer_id = m.customer_id
and main.quantity = m.qty
Obviously, name has no business being in this table, but you included it, so I did too...
SELECT x.*
FROM my_table x
JOIN
( SELECT customerid
, name
, MAX(quantity) max_quantity
FROM my_table
GROUP
BY customerid
, name
) y
ON y.customerid = x.customerid
AND y.name = x.name
AND y.max_quantity = x.quantity;

How to do a Select Distinct when returning XML

I have a a stored procedure that returns an XML, the problem now is that i want it to return distinct ClientID's but when I do this.. it says
The xml data type cannot be selected as DISTINCT because it is not comparable.
How can i do this? here is my Query
SELECT DISTINCT ClientTable.ClientID,
ClientTable.ClientAddress,
ClientTable.RetailStore,
ClientTable.PhoneNumber,
ClientTable.City,
ClientTable.Amount,
(SELECT Rating = IsNull(AVG(Rate), 0),
NumberRates = IsNUll(COUNT(ClientID), 0)
FROM ReviewsTable
WHERE ReviewsTable.ClientID = ClientTable.ClientID
FOR XML PATH(''), TYPE)
FROM ClientTable
INNER JOIN ClientTypes
ON ClientTable.ClientID = ClientTypes.ClientID
WHERE ClientTable.ClientID IN (SELECT myFreeTextTableID
FROM myFreeTextTable
WHERE FREETEXT(*, #Keyword))
OR
ClientTypes.ClientID IN (SELECT myFreeTextTableID
FROM myFreeTextTable
WHERE FREETEXT(*, #Keyword))
ORDER BY ClientTable.Order ASC
FOR XML AUTO, TYPE, ELEMENTS
I'm not even going to try to reproduce your schema or data, but what about this query?
;WITH ft AS
(
SELECT ClientID = myFreeTextTableID
FROM myFreeTextTable WHERE FREETEXT(*, #Keyword)
),
c AS
(
SELECT DISTINCT
c.ClientID,
c.ClientAddress,
c.RetailStore,
c.PhoneNumber,
c.City,
c.Amount,
c.[Order]
FROM dbo.ClientTable AS c
INNER JOIN dbo.ClientTypes AS t
ON c.ClientID = t.ClientID
WHERE EXISTS
(
SELECT 1 FROM ft
WHERE ClientID IN (c.ClientID, t.ClientID)
)
)
SELECT
c.ClientID,
c.ClientAddress,
c.RetailStore,
c.PhoneNumber,
c.City,
c.Amount,
Rating = (SELECT COALESCE(AVG(Rate), 0),
NumberRates = COALESCE(COUNT(ClientID), 0)
FROM ReviewsTable
WHERE ReviewsTable.ClientID = c.ClientID
FOR XML PATH(''), TYPE)
FROM c
ORDER BY c.[Order]
FOR XML AUTO, TYPE, ELEMENTS;