In the query below #processtable is a table variable and temp is a derived table when I am trying to join them I am getting the following error:
The column prefix 't' does not match with a table name or alias name used in the query.
SELECT t.Order
,CONVERT(NVARCHAR, temp.[DateTime], 101) AS [DateTime]
,t.Status
,t.Domain
,t.Media
,t.Approved
,t.CreatedBy
FROM #ProcessTable t
JOIN (SELECT MAX(Id),Order FROM OrderDetail OD WHERE OD.Order = t.Order) temp
ON temp.Order = t.Order
ORDER BY temp.[DateTime] DESC, Approved ASC
Try this:
SELECT t.Order
,CONVERT(NVARCHAR,temp.[DateTime],101) AS [DateTime]
,t.Status
,t.Domain
,t.Media
,t.Approved
,t.CreatedBy
FROM #ProcessTable t
JOIN (SELECT MAX(Id) AS LatestId, Order FROM OrderDetail OD GROUP BY Order) temp
ON temp.Order = t.Order
ORDER BY temp.[DateTime] DESC, Approved ASC
Note, I've remove the OD.Order = t.Order clause in the nested SELECT and added in a GROUP BY. The condition alongside that join (temp.Order = t.Order) does the filtering so doesn't need to be in the nested select - it was causing the error. Plus as you're using an aggregate function (MAX), you need the GROUP BY.
Also, I've given an alias for MAX(Id) to be returned as
You were almost right...You dont need the where clause in side the derived table if your going to include it as one of the Join criteria.
SELECT
t.Order
,CONVERT(NVARCHAR,temp.[DateTime],101) AS [DateTime]
,t.Status
,t.Domain
,t.Media
,t.Approved
,t.CreatedBy
FROM #ProcessTable t
JOIN (SELECT MAX(Id) AS MaxID,Order, Max([DateTime]) AS [DateTime] FROM OrderDetail OD Group By Order) temp
ON temp.Order = t.Order
ORDER BY temp.[DateTime] DESC, Approved ASC
I don't think you can reference the t.Order in the subquery as such. You should simply rely on the join to handle that clause.
E.g. simply remove the OD.Order = t.Order and allow the join clause to handle it.
Related
This is my first query:
select
r.[ProductID], [Name],
[Color], [UnitPrice]
from
[Production].[Product] r
inner join
[Sales].[SalesOrderDetail] d on d.productid = r.productid
This is my second query:
select [ProductID], [Name], [color]
from [Production].[Product] o
where [ProductID] in (select [UnitPrice]
from [Sales].[SalesOrderDetail] s
where s.ProductID = o.ProductID)
The first query returns correctly what I want to achieve, but the second query returns null. I want to use the second query to have the same result. Is that possible?
You can use exists :
select p.*
from product p
where exists (select 1 from SalesOrderDetail sd where sd.productid = p.product);
Your second query is not same as first query. It is comparing ProductID against UnitPrice which is invalid. Should produce no result.
For original version of query you can just change the sub query unit price with Productid :
where [ProductID] in (select sd.productid from SalesOrderDetail sd)
However, if you want unitprice (which is available in SalesOrderDetail) then this subquery will not help you. You need JOIN instead.
In my calculated data layer, I am attempting to populate a Customer's postcode at the time of the order, a sub sample of the table being populated is as follows:
CustomerOrders
(
CustomerID varchar(20),
...
OrderDate date,
...
CustomerPostcodeAtTimeOfOrder varchar(10)
)
This table is a join of the Customers table, the Orders table and the CustomerAddress table which looks like follows:
CustomerAddress
(
CustomerID varchar(20),
AddressType varchar(10),
/*
AddressDetails
*/
StartDate date,
EndDate date,
AddressRank int
)
It is quite conceivable that a customer may have recorded addresses of various types for a single date so the intention when populating the CustomerOrders table is to join as below:
SELECT *
FROM Customers c
LEFT JOIN Orders o
ON o.CustomerID = c.CustomerID
OUTER APPLY
(
SELECT TOP 1 Postcode
FROM CustomerAddress ca
WHERE ca.CustomerID = c.CustomerID
AND o.OrderDate BETWEEN ca.StartDate AND ca.EndDate
ORDER BY AddressRank
)
However, the performance hit I am getting by adding this join to the query means that returning 1000 rows goes from taking 4 seconds to taking 106 seconds.
Just to note, I have added a non-clustered index on the Address table too. The definition of which is as below:
CREATE NONCLUSTERED INDEX (IX_CustomerAddress)
ON CustomerAddress (StartDate, EndDate)
INCLUDE (AddressRank, CustomerID, Postcode)
I'm looking for any suggestions on the best way to tackle this issue please?
I'm not completely sure if this will return results faster, but you can rewrite your query like this:
;WITH OrderAddress AS
(
SELECT o.*,
ca.Postcode,
RN = ROW_NUMBER() OVER(PARTITION BY CustomerID ORDER BY AddressRank DESC)
FROM CustomerAddress ca
INNER JOIN Orders o
ON ca.CustomerID = c.CustomerID
AND o.OrderDate BETWEEN ca.StartDate AND ca.EndDate
)
SELECT *
FROM Customers c
LEFT JOIN ( SELECT *
FROM OrderAddress
WHERE RN = 1) o
ON o.CustomerID = c.CustomerID;
You should also post the index definition on the Address table.
I need to query the addresses of top 500 customers (best buyers). Many companies have multiple addresses.
The tables with data:
CustomerInfo
CustomerAddress
TransactionInfo
TransactionElements
My query looks this way:
select Customername, CustomerStreet --etc
from CustomerInfo
join CustomerAddress on CustomerID = Add_CustID
join TransactionInfo on Trn_CustID = CustomerID
JOIN TransactionElements ON Trn_CustID = TrE_CustID
GROUP BY CustomerName, CustomerStreet --etc
ORDER BY SUM (TrE_TranValue) DESC
It returns multiple addresses of a single company, I need just one.
One approach would be to use a CTE (Common Table Expression) if you're on SQL Server 2005 and newer (you aren't specific enough in that regard).
With this CTE, you can partition your data by some criteria - i.e. your CustomerId - and have SQL Server number all your rows starting at 1 for each of those "partitions", ordered by some criteria.
So try something like this:
;WITH CustomerAndAddress AS
(
SELECT
c.Customername, ca.CustomerStreet ,
ROW_NUMBER() OVER(PARTITION BY c.CustomerId ORDER BY ca.AddressID DESC) AS 'RowNum'
FROM
dbo.CustomerInfo c
INNER JOIN
dbo.CustomerAddress ca ON c.CustomerID = ca.Add_CustID
WHERE
......
)
SELECT
Customername, CustomerStreet
FROM
CustomerAndAddress
WHERE
RowNum = 1
Here, I am selecting only the "first" entry for each "partition" (i.e. for each CustomerId) - ordered by some criteria (I just arbitrarily picked AddressID from the address - adapt as needed) you need to define in your CTE.
Does that approach what you're looking for??
Something like this will work from sqlserver 2005+. I also suggest adding some aliasses to your tables and refer to those.
select CI.Customername, CA.CustomerStreet --etc
from CustomerInfo CI
cross apply
(select top 1 Customername, CustomerStreet --etc
from CustomerAddress where CustomerID = CI.Add_CustID) CA
join TransactionInfo TI on TI.Trn_CustID = CI.CustomerID
JOIN TransactionElements ON CI.CustomerID = TE.TrE_CustID
GROUP BY CustomerName, CustomerStreet --etc
ORDER BY SUM (TrE_TranValue) DESC
If CustomerInfo has many CustomerAddress, this query will make CustomerInfo returned for each CustomerAddress (a cartesian product) :
join CustomerAddress on CustomerID = Add_CustID
So if you need to get only one address you have to add conditions needed to choose single CustomerAddress :
join CustomerAddress on CustomerID = Add_CustID where <conditions>
select first(orderid), accountid
from [Order]
group by AccountId
order by DateCreated desc
first() is invalid function.
max() does not work for unique identifiers
How would I get the last orderid created for all accounts? Thanks.
Something like (untested):
;WITH CTE_LatestOrders AS (
select accountid, lastcreated = max(datecreated)
from [Order]
group by accountid
)
select
accountid, orderid
from
[Orders] o
join CTE_LatestOrders l
on o.AccountID = l.AccountID
and o.datecreated = l.lastcreated
Max() does work for unique identifiers as of MS SQL 2012
You can proceed with below as well.
Select Temp.orderid, T.AccountId, T.DateCreated
From
(
Select AccountId, max(DateCreated) as DateCreated
From [Order]
Group By AccountId
)T
Inner Join [Order] Temp on Temp.AccountId = T.AccountId
AND Temp.DateCreated = T.DateCreated
A CTE is not a UDT/temp table; think of a CTE as a view that is defined only for your current query. Just like a view, a CTE is expanded and folded into the overall query plan. Global optimization will still occur, but do not think that just because you use a CTE you will only execute the query once. Here is a trivial example that fits in this space: WITH vw AS ( SELECT COUNT(*) c FROM Person ) SELECT a.c, b.c FROM vw a, vw b; The query plan will clearly show two scans/aggregations and a join instead of just projecting the same result twice.
I am trying to join a table variable table and another table.
#ProcessTbl OrderDetail
Order ID
Status Order
Approved DateTime
Domain Status
OrderDetail table has multiple columns for same order. For example
ID Order DateTime Status
1 1 11-17-10 Recived
2 1 11-18-10 Processing
3 1 11-19-10 shipped
so what i want the join to do is take the order number from #processtbl(table variable)
and for max(id) get the datetime in this case the max id is 3
so my result should be
order status approved domain datetime
1 shipped true finance 11-19-10
SELECT t.order
,[od.DateTime]
,t.Status
,t.Domain
,t.Approved
FROM #ProcessTable t
JOIN OrderDetail od ON od.order= t.order
WHERE od.ID = (SELECT MAX(id) FROM orderdetail WHERE od.order = t.order )
ORDER BY od.[DateTime], Approved ASC
But I am still getting duplicate records , looks like it is joning both the tables.
How can I get distinct records?
select p.order, od.status, p.approved, p.domain, od.datetime
from #ProcessTable p
inner join (
select Order, max(ID) as MaxID
from OrderDetail
group by Order
) odm
inner join OrderDetail od on odm.Order = od.Order
and odm.MaxID = od.ID
Just a thought, have you tried to perform a SELECT DISTINCT?
WHERE od.ID = (SELECT MAX(id) FROM orderdetail WHERE od.order = t.order )
The od.order is not referencing the orderdetail table in the sub query but the instance outside.
Try something like: WHERE od.ID = (SELECT MAX(id) FROM orderdetail as od1 WHERE od1.order = t.order )