How to combine these 2 SQL query results? - sql

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'

Related

SQL add STUFF function into this query

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

SQL WHERE Temporary Column

I have this MSSQL Query which works
SELECT c.CategoryName + ' (' + cast(count(ic.CategoryId) as varchar(255)) + ')' AS
CategoryName, count(ic.CategoryId) AS NumPhotos,
c.Slug, c.ParentCategoryId, c.Id
FROM Categories
c LEFT JOIN
ItemCategories ic
on ic.CategoryId = c.Id
GROUP BY c.CategoryName, c.slug, c.ParentCategoryId, c.id
ORDER BY ParentCategoryId DESC
And I want to return only rows, WHERE NumPhotos>0 but temporary columns are not allowed on SQL WHERE clause
The having clause is the canonical solution to your problem. However, I suspect that an inner join would also be appropriate:
SELECT c.CategoryName + ' (' + cast(count(ic.CategoryId) as varchar(255)) + ')' AS CategoryName,
count(ic.CategoryId) AS NumPhotos,
c.Slug, c.ParentCategoryId, c.Id
FROM Categories c INNER JOIN
ItemCategories ic
on ic.CategoryId = c.Id
GROUP BY c.CategoryName, c.slug, c.ParentCategoryId, c.id
ORDER BY ParentCategoryId DESC;
Without sample data, it is hard to be sure, but I'm pretty sure this does the same thing.
The advantage of an inner join is that it might be more efficient, because less (maybe only slightly less) data would be processed and the optimizer has more opportunities to pick the best join algorithm.
Existing comments have given adequate answers, but here is another solution, using a "virtual table":
SELECT * FROM (
SELECT c.CategoryName + ' (' + cast(count(ic.CategoryId) as varchar(255)) + ')' AS
CategoryName, count(ic.CategoryId) AS NumPhotos,
c.Slug, c.ParentCategoryId, c.Id
FROM Categories
c LEFT JOIN
ItemCategories ic
on ic.CategoryId = c.Id
GROUP BY c.CategoryName, c.slug, c.ParentCategoryId, c.id
)
WHERE NumPhotos>0
ORDER BY ParentCategoryId DESC

sqlite return subquery multi column

I have a sqlite subquery with the following query which is calculating the hours and labour_rate. The only issue I now have is can I get the two columns from my subquery to output in the main query. I've tried to layout the query according to some of the web tutorials but need that little bit of help to get me over the finish line as I keep getting a syntax error
SELECT c.customerID, c.customer, sum( ifnull(il.line_price, 0 ) )/10000 AS net,
FROM customer AS c
LEFT JOIN invoice AS i
ON c.customerID = i.customerID
LEFT JOIN invoice_line AS il
ON i.invoiceID = il.invoiceID
(SELECT sum(( ifnull(tl.mon,0) + ifnull(tl.tues,0) + ifnull(tl.wed,0) + ifnull(tl.thurs,0) + ifnull(tl.fri,0) + ifnull(tl.sat,0) + ifnull(tl.sun,0) ) * s.cost_rate)/10000 AS labour_rate,
sum(( ifnull(tl.mon,0) + ifnull(tl.tues,0) + ifnull(tl.wed,0) + ifnull(tl.thurs,0) + ifnull(tl.fri,0) + ifnull(tl.sat,0) + ifnull(tl.sun,0) ))/10000 AS
FROM timesheet_line AS tl
LEFT JOIN timesheet AS t
ON tl.timesheetID = t.timesheetID
LEFT JOIN staff AS s
ON t.staffID = s.staffID
WHERE (c.customerID = tl.customerID) AND (t.date BETWEEN '2014-03-01' AND '2015-12-01')
GROUP BY tl.customerID) AS time1
WHERE (i.date BETWEEN '2014-03-01' AND '2015-12-01') AND (time1.customerID = tl.customerID)
GROUP BY c.customerID
ORDER BY c.customer ASC
There are a few syntax errors in here. The first (and possibly most important) is you have to JOIN your subquery to the rest of the result set. So after
LEFT JOIN invoice_line AS il
ON i.invoiceID = il.invoiceID
you will need to add another JOIN statement:
LEFT JOIN
(SELECT
SUM(...) AS labour_rate,
SUM(...) AS hours,
tl.customerID
FROM
...) AS time1
ON <your join condition>
You will have to select some sort of field in your sub query that you can join back to the the invoice on i.e. tl.customerID.
Also, in your subquery you cannot reference a field that is outside of it, so where you have WHERE (c.customerID = tl.customerID) in your subquery it will fail because you are trying to reference c.<fieldname>. It needs to be moved to the ON part of the JOIN clause. Once you get your JOIN working correctly then you can just change your outer-most SELECT to something like
SELECT c.customerID, c.customer, sum(ifnull(il.line_price,0))/10000 AS net, time1.labour_rate, time1.hours
Here's an example of how I would do it:
SELECT c.customerID, c.customer, sum( ifnull(il.line_price, 0 ) )/10000 AS net, time1.labour_rate, time1.[hours]
FROM customer AS c
LEFT JOIN invoice AS i
ON c.customerID = i.customerID
LEFT JOIN invoice_line AS il
ON i.invoiceID = il.invoiceID
LEFT JOIN
(SELECT
sum(( ifnull(tl.mon,0) + ifnull(tl.tues,0) + ifnull(tl.wed,0) + ifnull(tl.thurs,0) + ifnull(tl.fri,0) + ifnull(tl.sat,0) + ifnull(tl.sun,0) ) * s.cost_rate)/10000 AS labour_rate,
sum(( ifnull(tl.mon,0) + ifnull(tl.tues,0) + ifnull(tl.wed,0) + ifnull(tl.thurs,0) + ifnull(tl.fri,0) + ifnull(tl.sat,0) + ifnull(tl.sun,0) ))/10000 AS [hours],
tl.customerID
FROM timesheet_line AS tl
LEFT JOIN timesheet AS t
ON tl.timesheetID = t.timesheetID
LEFT JOIN staff AS s
ON t.staffID = s.staffID
WHERE (t.date BETWEEN '2014-03-01' AND '2015-12-01')
GROUP BY tl.customerID) AS time1
ON c.customerID = time1.customerID
WHERE (i.date BETWEEN '2014-03-01' AND '2015-12-01')
GROUP BY c.customerID
ORDER BY c.customer ASC

SQL Error 1016 - Inner Joins

I'm trying to add inner joins to old SQL code to make it run more efficiently. But when I added them and tried to execute I get this error:
1016, Line 12 Outer join operators cannot be specified in a query containing joined tables
Here's the query:
select a.s_purchase_order as order_id,
a.order_type,
a.nobackorder,
a.order_note,
a.note,
a.rqst_dlvry_date,
b.customer_name ,
c.store_name,
(c.store_name + ',' + isnull(c.address1 + ',', ' ') + isnull(c.city + ',', ' ') + isnull(c.state_cd+ ',', ' ') + isnull( c.zipcode, ' ')) as store_info,
d.supplier_account
from VW_CustomerOrder a, Customer b, Store c, eligible_supplier d
where a.customer = c.customer
and a.store = c.store
and a.customer = b.customer
and c.customer *= d.customer
and c.store *= d.store
and a.supplier *= d.supplier
and a.purchase_order = #order_id
and a.customer = #customer_id
and a.store=#store_id
and a.supplier = #supplier_id
Any idea what's causing it? I'm guessing it has something to do with the isnull?
Did you try this? It replaces your commas between your tables with INNER JOIN and LEFT JOIN
select a.s_purchase_order as order_id,
a.order_type,
a.nobackorder,
a.order_note,
a.note,
a.rqst_dlvry_date,
b.customer_name ,
c.store_name,
(c.store_name + ',' + isnull(c.address1 + ',', ' ') + isnull(c.city + ',', ' ') + isnull(c.state_cd+ ',', ' ') + isnull( c.zipcode, ' ')) as store_info,
d.supplier_account
from VW_CustomerOrder a
INNER JOIN Customer b
ON a.customer = b.customer
INNER JOIN Store c
ON a.customer = c.customer
and a.store = c.store
LEFT JOIN eligible_supplier d
ON c.customer = d.customer
and c.store = d.store
and a.supplier = d.supplier
where a.purchase_order = #order_id
and a.customer = #customer_id
and a.store=#store_id
and a.supplier = #supplier_id
If you left your "*=" join operators in the code after you converted it to ANSI syntax, that would explain your error. Use = for all equality tests when using ANSI syntax -- the type of your JOIN should be explicit in the JOIN declaration itself (INNER, LEFT, RIGHT, etc.)

How can I use Sql to Order By This Statement?

How can I order the list 'widgets_spec by number of widgets?
select distinct
m.p_c_id
,(select distinct '<li>' +convert(varchar,widgets) + '<br> '
from dbo.spec_master m2
where m.p_c_id = m2.p_c_id and widgets is not null
for xml path(''), type).value('.[1]', 'nvarchar(max)'
) as widgets_spec
from dbo.spec_master m
inner join dbo.ProductVaration pv on pv.p_c_id = m.p_c_id
inner join dbo.Varation v on v.varation_id = pv.varation_type_id
where v.varation_id = 4
group by m.p_c_id
Right now output looks like:
<li>10<br> <li>12<br> <li>15<br> <li>8<br>
When I want it to look like:
<li>8<br> <li>10<br> <li>12<br> <li>15<br>
Thanks for your help.
EDIT: I'm trying to order the internal select statement that concatenates the values.
You do not need both Distinct and Group By. You should use one or the other. In this case, I believe you have to use Group By for it to work.
Select m.p_c_id
, (
Select '<li>' + Cast( m2.num_of_lights As varchar(10)) + '<br /> '
From dbo.spec_master As m2
Where m.p_c_id = m2.p_c_id
And m2.num_of_lights Is Not Null
Group By m2.num_of_lights
Order By m2.num_of_lights
For Xml Path(''), type).value('.[1]', 'nvarchar(max)'
) As numLights_spec
From dbo.spec_master As m
Inner Join dbo.ProductVaration As pv
On pv.p_c_id = m.p_c_id
Inner Join dbo.Varation As v
On v.varation_id = pv.varation_type_id
Where v.varation_id = 4
Group by m.p_c_id
select distinct
m.p_c_id
,(select distinct '<li>' +convert(varchar,num_of_lights) + '<br> '
from dbo.spec_master m2
where m.p_c_id = m2.p_c_id and num_of_lights is not null
ORDER BY convert(varchar,num_of_lights)
) as numLights_spec
from dbo.spec_master m
inner join dbo.ProductVaration pv on pv.p_c_id = m.p_c_id
inner join dbo.Varation v on v.varation_id = pv.varation_type_id
where v.varation_id = 4
group by m.p_c_id
) As SubA
Some of the other answers here won't work, since ordering by the now-varchar num_of_lights will put '8' after '15' as is happening now. You want to order the numLights numerically, which isn't going to happen with those html tags around them. You can add a subselect to your subselect so that you order them, then select them with the tags around them. Example (not tested):
SELECT * FROM (
select distinct
m.p_c_id
,(select distinct '<li>' +convert(varchar,num_of_lights) + '<br> '
from (select distinct p_c_id, num_of_lights from dbo.spec_master order by num_of_lights) m2
where m.p_c_id = m2.p_c_id and num_of_lights is not null
for xml path(''), type).value('.[1]', 'nvarchar(max)'
) as numLights_spec
from dbo.spec_master m
inner join dbo.ProductVaration pv on pv.p_c_id = m.p_c_id
inner join dbo.Varation v on v.varation_id = pv.varation_type_id
where v.varation_id = 4
group by m.p_c_id
Personally, I'd just add the html tags in whatever back-end code is getting the result of the query.