SQL Server : bring up columns from a sub query - sql

I am pretty stuck with this (SQL Server 2008 R2).
I have a tables called orders:
Orders:
orderid details
--------------------
1 my order
I then have a custom fields table.
Custom_fields:
rel_orderid fieldname numericvalue textvalue datevalue
-----------------------------------------------------------
1 auction 0 My auction
1 date 0 01/01/2014
I am trying to get
orderid details auction date (on one row)
-------------------------------------------------
1 my order my auction 01/01/2014
Hope that makes sense but I'm beat how to wrap up the custom_fields table into column headers and then only have 1 value (could be text value or date etc - only 1 will have data)
The auction and date and read form the fieldname column and then the values for each.

You can use max with case for this:
select o.orderid,
o.details,
max(case when c.fieldname = 'auction' then textvalue end) auction,
max(case when c.fieldname = 'date ' then datevalue end) datevalue
from orders o
join custom_fields c on o.orderid = c.rel_orderid
group by o.orderid

you can PIVOT in such a case.
select orderid,
details,
[auction],
[date]
FROM
(
select rel_orderid as orderid,
o.details,
fieldname,
(case when fieldname = 'auction'
then textvalue
when fieldname ='date'
then cast(datevalue AS varchar(128))
end) value
FROM custom_fields
INNER JOIN orders o
on o.orderid = rel_orderid
) As OrderDetails
PIVOT
(
max(value)
for fieldname in ([auction],[date])
) pvt

If you want to avoid an aggregation, you can do this using joins:
select o.orderid, o.details, a.textvalue as auction, d.datevalue as dateval
from orders o left join
custom_fields a
on a.rel_orderid = o.orderid and a.fieldname = 'auction' left join
custom_fields d
on d.rel_orderid = o.orderid and d.fieldname = 'date';
The left join gives a value (NULL) even if there is no match.

Related

DISTINCT return same ID two times wrongly

This is my SQL query:
SELECT DISTINCT(ItemId), TCode, PartNumber,ModelNumber, ItemUOM
FROM #Results
This query returns:
ItemId TCode Source PartNumber ModelNumber ItemUOM
-----------------------------------------------------------------
1024 1000 NULL NULL EA
1024 1000 FLEX FLEX EA
#Result is a temp table I have used left join in that query
Why does SELECT DISTINCT return the same ItemID 1024 twice?
SELECT DISTCINT(I.ItemId),
(DENSE_RANK() OVER(ORDER BY I.ItemId ASC)) AS RowNumber,
(I.TCode), E.Name AS Source,
I.GoldenRecordNumber AS GoldenRecordNo, I.ItemCode AS MMRefNo,
I.ShortDescription AS ShortText, I.LongDescription AS POText,
Suppliers.Description AS Manufacturer, Suppliers.Name AS ManufacturerCode,
Suppliers.Abbreviation AS ManufacturerAbbr,
ItemSuppliers.ReferenceNo AS PartNumber, ItemSuppliers.ReferenceNo AS ModelNumber,
UOM.Name AS ItemUOM, MG.Name AS PSGC,
NM.Noun AS ClassName, NM.LongAbbrevation AS ClassDescription
INTO
#Results
FROM
Items I
LEFT JOIN
ItemSuppliers ON I.ItemId = ItemSuppliers.ItemsId
LEFT JOIN
Suppliers ON ItemSuppliers.ManufacturerId = Suppliers.SupplierId
LEFT JOIN
UnitOfMeasurement UOM ON UOM.UOMId = I.UOMId
LEFT JOIN
MaterialGroup MG ON MG.MaterialGroupId = I.MaterialGroupId
LEFT JOIN
NounModifiers NM ON NM.NounModifierId = I.NounModifierId
LEFT JOIN
AutoClass AC ON AC.ClassName = NM.Noun
LEFT JOIN
ERP E ON E.ERPId = I.ERPName
LEFT JOIN
NounModifierAttributes NMA ON NMA.NounModifierId =
NM.NounModifierId
LEFT JOIN
Attributes A ON A.AttributeId = NMA.AttributeId
LEFT JOIN
ItemAttributes IA ON IA.ItemId = I.ItemId
WHERE
(I.ItemCode LIKE '%'+'2001010088'+'%' )
SELECT 'Int' = COUNT(distinct(ItemId))
FROM #Results
WHERE (TCode IS NOT NULL OR MMRefNo IS NOT NULL)
SELECT DISTINCT(ItemId),
TCode, Source, GoldenRecordNo, MMRefNo, ShortText, POText,
Manufacturer, ManufacturerCode, ManufacturerAbbr, PartNumber, ModelNumber,
ItemUOM, PSGC, ClassName, ClassDescription
FROM
#Results
WHERE
(TCode IS NOT NULL OR MMRefNo IS NOT NULL)
AND RowNumber BETWEEN (1-1)*100 + 1 AND (((1-1) * 100 + 1) + 100) - 1
DROP TABLE #Results
if you are convinced the rows which are selected can be grouped together then it should work fine.
1. but if rows are having different data then distinct will not help.
2. use ltrim,rtrim to remove leading and trailing spaces.
example: distinct(ltrim(rtrim(ItemId)))
this will help if it due to spaces or for junk values
The behavior of DISTINCT works as expected. For instance, you could use GROUP BY clause to group them by ItemId, TCode to get top most records
SELECT
ItemId, TCode,
MAX(PartNumber) PartNumber, MAX(ModelNumber) ModelNumber,
MAX(ItemUOM), ...
FROM #Results
GROUP BY ItemId, TCode
In case any failure in GROUP BY clause use ranking function to assign the rank and get the record based on rank value.

SQL - Tracking Monthly Sales

I am writing a query to summarize sales by month. My problem is that my query only returns records for months with sales. For example, I am looking over a 15 month range. But for one specific part in the example below only 3 of the 15 months had sales.
I'm hoping to have 15 records show up and the other ones have 0's for sales. The reason I am hoping for the additional records is I want to take the standard deviation of this, and dropping records impacts that calculation.
Sample Code:
SELECT I.PartNumber as PartNumber,
YEAR(O.CreateDate) as CreateDateYear,
MONTH(O.CreateDate) as CreateDateMonth,
COUNT(*) as TotalDemand
FROM OrderDetails OD
INNER JOIN Orders O on O.Id = OD.OrderId
INNER JOIN Items I on I.Id = OD.ItemId
WHERE
O.CreateDate >= '1-1-2016'
AND O.CreateDate <= '3-31-2017'
AND I.PartNumber = '5144831-2'
GROUP BY I.PartNumber, YEAR(O.CreateDate) , MONTH(O.CreateDate);
Sample Current Output:
Part # | Year | Month | Demand
5144831-2 2017 1 1
5144831-2 2017 2 3
5144831-2 2016 3 1
Desired Output:
I would want an additional row such as:
5144831-2 2016 11 0
To show there were no sales in Nov 2016.
I do have a temp table #_date_array2 with the possible months/years, I think I need help incorporating a LEFT JOIN.
If you want to use left join, you would not be able to use it directly with the inner join. You can do the inner join inside the parenthesis and then do the left join outside to avoid messing with the results of left join. Try this:
SELECT Z.PartNumber as PartNumber,
YEAR(O.CreateDate) as CreateDateYear,
MONTH(O.CreateDate) as CreateDateMonth,
COUNT(Z.OrderId) as TotalDemand
FROM Orders O
LEFT JOIN
(
SELECT OrderId, PartNumber
FROM
OrderDetails OD
INNER JOIN Items I ON I.Id = OD.ItemId
AND I.PartNumber = '5144831-2'
) Z
ON O.Id = Z.OrderId
AND O.CreateDate >= '1-1-2016'
AND O.CreateDate <= '3-31-2017'
GROUP BY Z.PartNumber, YEAR(O.CreateDate) , MONTH(O.CreateDate);
To get a count of 0 for months with no order, avoid using count(*) and use count(OrderId) as given above.
Note - You will have to make sure the Orders table has all months and years available i.e. if there is no CreateDate value of, say, November 2016 in the Orders table(left table in the join), the output will also not produce this month's entry.
Edit:
Can you try this:
SELECT Z.PartNumber as PartNumber,
YEAR(O.CreateDate) as CreateDateYear,
MONTH(O.CreateDate) as CreateDateMonth,
COUNT(O.OrderId) as TotalDemand
FROM Orders O
RIGHT JOIN
(
SELECT OrderId, PartNumber
FROM
OrderDetails OD
INNER JOIN Items I ON I.Id = OD.ItemId
AND I.PartNumber = '5144831-2'
) Z
ON O.Id = Z.OrderId
AND O.CreateDate >= '1-1-2016'
AND O.CreateDate <= '3-31-2017'
GROUP BY Z.PartNumber, YEAR(O.CreateDate) , MONTH(O.CreateDate);
Assuming you have sales of something in every month, the simplest solution is to switch to conditional aggregation:
SELECT '5144831-2' as PartNumber,
YEAR(O.CreateDate) as CreateDateYear,
MONTH(O.CreateDate) as CreateDateMonth,
SUM(CASE WHEN I.PartNumber = '5144831-2' THEN 1 ELSE 0 END) as TotalDemand
FROM OrderDetails OD INNER JOIN
Orders O
ON O.Id = OD.OrderId INNER JOIN
Items I
ON I.Id = OD.ItemId
WHERE O.CreateDate >= '2016-01-01' AND
O.CreateDate <= '2017-03-31'
GROUP BY YEAR(O.CreateDate) , MONTH(O.CreateDate);
Note: This is something of a hack for solving the problem. More robust solutions involve generating the dates and using LEFT JOIN (or similar functionality). However, this is often the fastest way to get the result.
based on all of your comments on other posts etc it seems like you have a table that has a date range you want and you want to be able to run the analysis for multiple/all of the part numbers. So the main issue is you will need a cartesian join between your date table and partnumbers that were sold during that time in order to accomplish you "0"s when not sold.
;WITH cteMaxMinDates AS (
SELECT
MinDate = MIN(DATEFROMPARTS(CreateDateYear,CreateDateMonth,1))
,MaxDate = MAX(DATEFROMPARTS(CreateDateYear,CreateDateMonth,1))
FROM
#_date_array2
)
;WITH cteOrderDetails AS (
SELECT
d.CreateDateYear
,d.CreateDateMonth
,I.PartNumber
FROM
#_date_array2 d
INNER JOIN Orders o
ON d.CreateDateMonth = MONTH(o.CreateDate)
AND d.CreateDateYear = YEAR(o.CreateDate)
INNER JOIN OrderDetails od
ON o.Id = od.OrderId
INNER JOIN Items i
ON od.ItemId = i.Id
AND i.PartNumber = '5144831-2'
)
, cteDistinctParts AS (
SELECT DISTINCT PartNumber
FROM
cteOrderDetails
)
SELECT
d.CreateDateYear
,d.CreateDateMonth
,I.PartNumber
,COUNT(od.PartNumber) as TotalDemand
FROM
#_date_array2 d
CROSS JOIN cteDistinctParts p
LEFT JOIN cteOrderDetails od
ON d.CreateDateYear = od.CreateDateYear
AND d.CreateDateMonth = od.CreateDateMonth
AND p.PartNumber = od.PartNumber
GROUP BY
d.CreateDateYear
,d.CreateDateMonth
,I.PartNumber
To get ALL part numbers simply remove AND i.PartNumber = '5144831-2' join condition.

Query in SQL Server 2014 for a report (I need the last ROW of a table)

I'm using SQL Server 2014 and I have a problem with a query.
I want to have in my report, ALL the items of the order with ID_Order = 9 that have been delivered. And for the items that have been delivered at two times (Item Code = Art3 for example), I just want to have the last row, that means the last delivery of this Item, with NO repetition.
I already tried these two queries without success:
Attempt #1: DISTINCT
SELECT DISTINCT
Order.ItemCode, Delivery. Qty, Delivery.ID_Delivery,
Order.ID_Order
FROM
Delivery
INNER JOIN
Order ON Order.ID_Order = Delivery.ID_Order
WHERE
Order.ID_Order = '9'
Attempt #2: subquery
SELECT *
FROM
(SELECT
Order.ItemCode, Delivery.Qty,
FROM
Delivery
INNER JOIN
Order ON Order.ID_Order = Delivery.ID_Order
WHERE
Order.ID_Order = '9')
GROUP BY
a.ItemCode, a.Qty
Try this query --
;WITH CTE
AS (
SELECT C.ID_Order
,D.ID_Delivery
,C.ItemCode
,C.Quantity
,ROW_NUMBER() OVER (
PARTITION BY C.ItemCode ORDER BY D.ID_Delivery DESC
) AS RowNum
FROM Customer_Order C
INNER JOIN Delivery D ON C.ID_Order = D.ID_Order
AND C.ItemCode = D.ItemCode
WHERE C.ID_Order = 9
)
SELECT ID_Order
,ID_Delivery
,ItemCode
,Quantity
FROM CTE
WHERE RowNum = 1
SELECT
Order.ItemCode, Delivery. Qty, Delivery.ID_Delivery,
Order.ID_Order
FROM
Delivery
INNER JOIN
Order ON Order.ID_Order = Delivery.ID_Order
WHERE
Order.ID_Order = '9'
AND Delivery.ID_Delivery IN
(
SELECT MAX(ID_Delivery) FROM Delivery D WHERE D.ID_Order = Delivery.ID_Order GROUP BY D.ID_Order
)
I hope it will work for you.

How to apply WHERE clause to multiple SELECT statements in SQL Server

I am creating an query that selects data from multiple tables. I have completed all the query but now I have to apply the WHERE clause to the whole query.
I have 9 select statements, and these are working fine. Data is being selected from different tables. Now I want to declare date session and I want all data to be filtered according to the date provided. I am using the below query:
SELECT
(SELECT COUNT(DISTINCT OrderItems.ProductID)
FROM OrderItems) AS 'TotalSoldItemsDistinct',
(SELECT COUNT(OrderItems.ProductID)
FROM OrderItems) AS 'TotalSoldItemsInDistinct',
(SELECT COUNT(Orders.OrderID)
FROM Orders) AS 'TotalOrders',
(SELECT COUNT(Orders.OrderID)
FROM Orders
WHERE Orders.OrderStatusID = #CompleteOStatusID) AS 'CompleteOrders',
(SELECT COUNT(Orders.OrderID)
FROM Orders
WHERE Orders.OrderStatusID = #PendingOStatusID) AS 'PendingOrders',
(SELECT COUNT(Orders.ClientID)
FROM Orders
WHERE Orders.ClientID != #WalkingCustID) AS 'namedcustomers',
(SELECT COUNT(Orders.ClientID)
FROM Orders
WHERE Orders.ClientID = #WalkingCustID) AS 'WalkingCustomers',
(SELECT SUM(OrderItems.PurchasePrice)
FROM OrderItems) AS 'TotalPurchasePrice',
(SELECT SUM(OrderItems.SalePrice)
FROM OrderItems) AS 'TotalSalePrice'
I am selecting data from 2 tables named 'Orders' and 'OrderItems', I have column TransactionDate in 'Orders' table and column OrderDate in OrderItems table on that I want to use where filter. Can anybody please suggest how to apply filter to whole query?
You could try this
;with tempOrderItems AS
(
SELECT
COUNT(DISTINCT OrderItems.ProductID) AS 'TotalSoldItemsDistinct',
COUNT(OrderItems.ProductID) AS 'TotalSoldItemsInDistinct',
SUM(OrderItems.PurchasePrice) AS 'TotalPurchasePrice',
SUM(OrderItems.SalePrice) AS 'TotalSalePrice'
FROM OrderItems ori
WHERE OrderDate BETWEEN xxx AND yyy
)
, tempOrders AS
(
SELECT
COUNT(o.OrderID) AS 'TotalOrders',
SUM(CASE WHEN o.OrderStatusID = #CompleteOStatusID THEN 1 ELSE 0 END) AS 'CompleteOrders',
SUM(CASE WHEN o.OrderStatusID = #PendingOStatusID THEN 1 ELSE 0 END) AS 'PendingOrders',
SUM(CASE WHEN o.ClientID != #WalkingCustID THEN 1 ELSE 0 END) AS 'namedcustomers',
SUM(CASE WHEN o.ClientID = #WalkingCustID THEN 1 ELSE 0 END) AS 'WalkingCustomers'
FROM Orders o
WHERE TransactionDate BETWEEN xxx AND yyy
)
SELECT * FROM tempOrderItems
CROSS JOIN tempOrders
It is not fully clear what you want as a result, but here 2 approaches.
Try the following for selecting data from 2 tables at the same time (replace the date with your criteria):
SELECT * FROM Orders AS o INNER JOIN OrderItems AS i WHERE o.TransactionDate = '2015-02-12' AND i.OrderDate = '2015-02-12';
The SELECT * selects all columns from both tables as a result and the WHERE ... AND ...-clause filters for results only with your defined date.
Try the following for selecting order item data only for Data that matches the date on a specific order.
SELECT i.* FROM Orders AS o INNER JOIN OrderItems AS i WHERE o.TransactionDate = i.OrderDate AND o.OrderID = '12345';
The SELECT i.* tells the query to only return the columns of the OrderItems. And the WHERE o.TransactionDate = i.OrderDate ensures that only order items from the same date of the order with the OrderID "12345" are returned (which is defined with the AND o.OrderID = '12345'. This would work given you have a field "OrderID" on your Order table and you want to use it as a criteria.

How to merge Two queries into one and result in one row

SELECT lp.lead_bucket_no ,
case when p.product = 'S-400' then qty end as 'S400' ,
case when p.product = 'Dish Antenna' then qty end as 'DishAntenna'
FROM lead_products lp INNER JOIN products p ON p.product_id = lp.product_id WHERE type = 'stock' GROUP BY lead_bucket_no ORDER BY lp.lead_bucket_no
and
SELECT lp.lead_bucket_no ,
case when p.product = 'S-400' then qty end as 'S400' ,
case when p.product = 'Dish Antenna' then qty end as 'DishAntenna'
FROM lead_products lp INNER JOIN products p ON p.product_id = lp.product_id WHERE type = 'order' GROUP BY lead_bucket_no ORDER BY lp.lead_bucket_no
how to merge these both query and and got record in single row. only type are different in both queries.
enter image description here
I think you just want OR (or IN) in the WHERE clause:
SELECT lp.lead_bucket_no,
SUM(case when p.product = 'S-400' then qty end) as S400,
SUM(case when p.product = 'Dish Antenna' then qty end) as DishAntenna
FROM lead_products lp INNER JOIN
products p
ON p.product_id = lp.product_id
WHERE type IN ('stock', 'order')
GROUP BY lead_bucket_no
ORDER BY lp.lead_bucket_no;
You also need some sort of aggregation for the expressions that are not in the GROUP BY clause. You may also want to aggregate by TYPE. It is unclear what you want for the final output.