Count Function with Linked Table - sql-server

I am attempting to count the number of parts ordered by each of our customers in 2013. However the returned results seem to be grouped by order number and not trader. I am using the following select statement;
SELECT orders.traderid, COUNT(orderitems.partid) AS configuredparts
FROM orders LEFT JOIN orderitems
ON orders.id = orderitems.orderid AND orders.ordertype = orderitems.ordertype
WHERE (orderitems.partid LIKE N'P%') AND (YEAR(orders.createddate) = 2013)
GROUP BY orders.traderid, orderitems.partid, orders.ordertype
HAVING (orders.ordertype = N'SO')
ORDER BY orders.traderid
an example of my results are
traderid configured parts
800001 3
800001 3
800001 2
800001 1
A00002 1
A00002 2
Any help is much appreciated

This answer gives the total number (count) of part ids in table [order items] by trader id in table [orders].
trader_id part_id total_parts
800001 P001 3
800001 P002 2
A00002 P001 1
If table [order items] has a qty column, you should change COUNT(oi.partid) to SUM(oi.qty).
SELECT
o.traderid as trader_id,
oi.partid as part_id,
COUNT(oi.partid) AS total_parts
FROM
orders as o
LEFT JOIN
orderitems as oi
ON
o.id = oi.orderid AND
o.ordertype = oi.ordertype
WHERE
(oi.partid LIKE N'P%') AND
(o.createddate >= '20130101') AND
(o.createddate < '20140101') AND
(o.ordertype = N'SO')
GROUP BY
o.traderid, oi.partid
ORDER BY
o.traderid, oi.partid
Last but not least, why does the caption have a linked table (server)?
If you are using a linked server you will need to use 4 part notation.
Linked_Server_Name.Database_Name.Schema_Name.Object_Name

give this a go
SELECT orders.traderid, COUNT(orderitems.partid) AS configuredparts
FROM orders LEFT JOIN orderitems AND orders.ordertype = orderitems.ordertype
ON orders.id = orderitems.orderid
WHERE (orderitems.partid LIKE N'P%') AND (orders.createddate >= '20130101')
AND (orders.createddate < '20140101') AND (orders.ordertype = N'SO')
GROUP BY orders.traderid
ORDER BY orders.traderid

Related

Find the average and total revenue by each sub-category for the categories which are among top 5 categories in terms of quantity sold? <SQL Server>

For this question, I have two tables and are as follows :
prod_cat_info --- This table has the following columns:
prod_cat : It contains the products' category names
prod_cat_id : It contains the products' category ID. Note that every product category has been assigned a unique ID. For example :: Lets say I have following product categories Books,Sports,Electronics. So these 3 product categories will be assigned product category ID as 1,2 & 3 respectively.
prod_subcat : It contains products' subcategories
prod_subcat_id : It contains products' subcategories ID
Now how this product subcategories are stored. For example : Lets say for product category "Books", I have 3 product subcategories like "Novels", "Schoolbooks" & "Fiction". So in this case also, each and every product subcategory would be assigned an ID like 1,2,3 and so on.
Transactions --- This is another table which has the following columns :
total_amt : It contains amount paid by customer when a transaction took place.
Qty : It contains quantities ordered by customer of a particular product.
prod_subcat_id : It contains products' subcategories ID
prod_cat_id : It contains the products' category ID.
Cust_ID : It contains customer ID [Irrelevant column in case of this question]
What I did is, I break this question into 2 parts & wrote 2 separate queries. Query is given below. I am not able to figure out how to join these 2 queries in order to achieve the output.
For my query1 - I have fetched all the product subcategories.
In query2 - I have fetched the top 5 product categories based on quantities sold.
Now I feel that Query2 can be used as a subquery in Query1 inside WHERE clause.
But It may require some modifications because what I know is that orderby can't be used in subquery & also result of a subquery will be a single output.
Therefore, I need some help on how can I combine/modify this query in order to achieve the result.
**Query1**
select P.prod_subcat as Product_SubCategory,
AVG(cast(total_amt as float)) as Average_Revenue,
SUM(cast(total_amt as float)) as Total_Revenue
from Transactions as T
INNER JOIN prod_Cat_info as P
ON T.prod_cat_code = P.prod_cat_code AND T.prod_subcat_code =
P.prod_sub_cat_code
group by P.prod_subcat
**Query2**
select top 5 P.prod_cat, sum(Cast(Qty as int)) AS Quantities_sold from
prod_cat_info as P
inner join Transactions as T
ON P.prod_cat_code = T.prod_cat_code AND P.prod_sub_cat_code =
T.prod_subcat_code
group by P.prod_cat
order by sum(Cast(Qty as int)) desc
If you have a TOP operator with ORDER BY, which is exactly your case, then you can use order by in a subquery. Because in this case the ORDER BY is used to determine the rows returned by the TOP clause.
And for multiple values you can use IN operator
select P.prod_subcat as Product_SubCategory,
AVG(cast(total_amt as float)) as Average_Revenue,
SUM(cast(total_amt as float)) as Total_Revenue
from Transactions as T
INNER JOIN prod_Cat_info as P
ON T.prod_cat_code = P.prod_cat_code AND T.prod_subcat_code =
P.prod_sub_cat_code
WHERE P.prod_cat_code IN (
select top 5 P.prod_cat_code
from prod_cat_info as P
inner join Transactions as T
ON P.prod_cat_code = T.prod_cat_code AND P.prod_sub_cat_code =
T.prod_subcat_code
group by P.prod_cat
order by sum(Cast(Qty as int)) desc
)
group by P.prod_subcat
Select prod_cat, prod_subcat , avg(total_amt) as average_amount , sum(total_amt) as total_amount
From transactions as t
inner join prod_cat_info as p
on t.prod_subcat_code=p.prod_sub_cat_code and t.prod_cat_code = p.prod_cat_code
Where prod_cat in
(Select Top 5 prod_cat
From transactions as t
inner join prod_cat_info as p
on t.prod_subcat_code=p.prod_sub_cat_code and t.prod_cat_code = p.prod_cat_code
Where total_amt > 0 and qty > 0
Group by prod_cat
Order by count(qty) desc)
Group by prod_subcat
Order by prod_cat asc;

SQL query to bring back all orders only if all order details are in a list

I have an orders table that contains a lot of order specific info that is irrelevant to the question. However, I then have an orderDetails table that has a foreign key (orders.id == orderDetails.orderId). In this orderDetails, a customer can select to order lots of flavors of a product, each flavor gets a new entry in this table linked back to the main order.
What I want to do is select all the orders where ALL the flavors are present in the order. So, if an order has apple, peach and orange and I query for apple and peach, it wouldn't return that order because orange wasn't in my query.
I have tried subqueries and so on, but I feel like the only way to solve it is with looping each order and looking at the details, but that is horribly inefficient. Any thoughts?
SELECT *
FROM orders
WHERE id IN (SELECT orderId
FROM orderdetails
WHERE flavor IN('apple', 'peach', 'orange'))
AND isInvoiced = 1
AND isShipped = 0
AND isOnHold = 0
So, if I don't have any peach in stock, I want to see orders that do not contain any peach:
SELECT *
FROM orders
WHERE id IN (SELECT orderId
FROM orderdetails
WHERE flavor IN ('apple', 'orange'))
AND isInvoiced = 1
AND isShipped = 0
AND isOnHold = 0
The problem with the existing query here is that it returns everything because it just says, sure, you asked for apple... sure you asked for orange and this order contains those so I will return it. I need it to be ALL or nothing.
In the real database, the flavors are ID's, I just simplified it for this example.
Database tables were requested... I'll go ahead and list them as they really exist.
orders
-------
id
isInvoiced
isShipped
isOnHold
orderDetails
------------
id
orderId
flavorId
One more edit, this is my original failed attempt:
select * from orders WHERE id in
(
select orderId from orderdetails where flavorId in
(
'616a6d8e-be2e-4740-820b-1cad2a3d89b5',
'5d02f25b-f717-4079-97af-8aa444fe26b1',
'3504be8b-bebe-4b69-a22f-724d90003f99',
'c0a5a036-6dbe-417d-afcf-644f5520f2a8',
'29bfdea5-f270-44f0-9f48-245992af8401',
'29e53a21-4fdc-40e7-8bd9-733058a48097',
'60a90505-b9f5-4a60-8444-a35c2477d4a5',
'c9b93e89-98b0-4765-aedf-3a5f9d182c77',
'651ea709-a885-4f12-ad53-3290e8f0b18f',
'c5962375-d4d5-4ec7-82c0-0293475e6204',
'7faeffc0-fa88-4904-a6a9-7201949b23fd',
'24979b0d-7200-4a7d-9271-d26912d1b16d',
'5efeb81a-7642-4484-b8fc-62544bc8bff7'
)
)
and isInvoiced = 1 and isShipped = 0 and isOnHold = 0
That list of ID's would change based on what flavors are actually in stock.
basically you can just GROUP BY flavor with condition HAVING COUNT(*) = 3. So orders with those 3 flavor will be listed
select *
from orders o
where exists
(
select x.flavor
from orderdetails x
where x.orderId = o.id
and x.flavor in ('apple', 'peach', 'orange')
group by x.flavor
having count(*) = 3
)
and isInvoiced = 1
and isShipped = 0
and isOnHold = 0
You can use count function to make sure all flavors are represented.
select o.*
from orders o
inner join
(
select orderId, count(*) as flavorCount
from orderdetails
where flavor in ('apple', 'peach', 'orange')
group by orderId
) as t1
on o.orderId = t1.orderId
and isInvoiced = 1
and isShipped = 0
and isOnHold = 0
and t1.falvourCount = 3;
It would be simpler if you have a list of out-of-stock and in-stock flavors.
So if for example 'peach' is out of stock , and 'apple' and 'orange' are in stock, the following query will produce Orders that have only 'apple' OR 'orange' :
SELECT * FROM orders
WHERE
id IN (SELECT id FROM orderdetails WHERE flavor IN ('apple','orange') ) -- in stock
AND
id NOT IN (SELECT id FROM orderdetails WHERE flavor IN ('peach') ) --out of stock
What do you think ?
The question completely changed via this comment "I realize now I left out one very important part in that each order may have 1 or any number of flavors, not all have to be present."
The following query meets the original requirements: "What I want to do is select all the orders where ALL the flavors are present in the order" & "I need it to be ALL or nothing."
An order might have more than one item referring to a flavor ("apple pie", and "apple cake" for example), so I recommend you use 3 case expressions in a having clause to guard against this, whilst still achieving your objective:
select o.*
from orders as o
inner join (
select orderId
from orderdetails
group by orderId
having sum(case when flavor = 'apple' then 1 else 0 end) > 0
and sum(case when flavor = 'peach' then 1 else 0 end) > 0
and sum(case when flavor = 'orange' then 1 else 0 end) > 0
) as od on o.id = od.orderid
where o.isInvoiced = 1
and o.isShipped = 0
and o.isOnHold = 0
Note that the use of an inner join limits the orders listed to only those that refer to all 3 flavors.
This query is demonstrated here: http://rextester.com/AKMM54555

Duplicated rows on getting Categories of a Publication

I have a table of Publications
Id | Title | Content ...
1 | 'Ex title 1' | 'example content 1'
2 | 'Ex title 2' | 'example content 2'
...
And a table of Categories
CategoryId | PublicationId
1 | 1
2 | 1
2 | 2
3 | 2
...
So a Publication could have one or many categories.
I am trying to get the first 10 publications and their categories on a single query, like that:
SELECT [Publication].Id, [Publication].Title, [Publication].Content, [PublicationCategory].CategoryId
FROM [Publication]
LEFT JOIN [PublicationCategory] ON [Publication].Id = [PublicationCategory].Id
ORDER BY [Publication].Id DESC
OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY
But I am getting duplicated values because of diferents categories ids, which is the better way to get 10 publications and their categories and not getting duplicated rows (because of duplicated rows, i got duplicated publications)
You can first pick the TOP 10 Publications and then put a JOIN with the Category table like following query to get all the categories.
SELECT [Publication].*,[PublicationCategory].[categoryid]
FROM
(
SELECT TOP 10 [Publication].id,
[Publication].title,
[Publication].content
FROM Publications [Publication]
ORDER BY [Publication].Id DESC
) [Publication]
INNER JOIN Categories [PublicationCategory]
ON [Publication].id = [PublicationCategory].publicationid
DEMO
Use a CTE to number your publlication, and then JOIN onto your table PublicationCategory and filter on the value of ROW_NUMBER():
WITH RNs AS(
SELECT P.Id, P.Title, P.Content,
ROW_NUMBER() OVER (ORDER BY P.ID DESC) AS RN
FROM Publication P)
SELECT RNs.Id, Rns.Title, RNs.Content,
PC.CategoryId
FROM RNs
LEFT JOIN PublicationCategory PC ON RNs.Id = PC.Id
WHERE RNs.RN <= 10;
I Think the best answer is the #PSK's but What if a publication is not categorized? (weird case but if is not validated maybe could happen) so you can add a left join and always get at least the 10 publications, if a publication has no category you still will get it but with a NULL category
SELECT [Publication].*,[PublicationCategory].[categoryid]
FROM
(
SELECT TOP 10 [Publication].id,
[Publication].title,
[Publication].content
FROM Publications [Publication]
ORDER BY [Publication].Id DESC
) [Publication]
LEFT JOIN Categories [PublicationCategory]
ON [Publication].id = [PublicationCategory].publicationid

How to display only the MAX results from a query

I am new to writing MS SQL queries and I am trying to display only the record with the highest field named RecordVersion.
Below is the query that works but displays all records:
SELECT
PriceCalendars.PriceProgramID,
PriceCalendars.EffectiveDateTime,
PriceSchedules.Price,
PriceSchedules.PLU,
items.Descr,
PriceSchedules.LastUpdate,
PriceSchedules.LastUpdatedBy,
PriceSchedules.RecordVersion,
PriceSchedules.PriceScheduleUniqueID
FROM
PriceCalendars
INNER JOIN PriceSchedules ON PriceCalendars.PriceProgramID = PriceSchedules.PriceProgramID
INNER JOIN items ON PriceSchedules.PLU = items.PLU
WHERE
(PriceSchedules.PLU = 'SLS10100103')
AND (PriceCalendars.EffectiveDateTime = '2016-03-22')
Here are the query results:
PriceProgramID EffectiveDateTime Price PLU Descr LastUpdate LastUpdatedBy RecordVersion PriceScheduleUniqueID
1 2016-03-22 00:00:00.000 35.00 SLS10100103 Architecture Adult from NP POS 2015-01-22 07:53:15.000 GX70,83 9 569
1 2016-03-22 00:00:00.000 32.00 SLS10100103 Architecture Adult from NP POS 2014-02-25 16:22:46.000 GX70,83 5 86180
The first line of the results has RecordVersion being 9 and the second line results is 5, I only want the higher record displaying, the one that returned RecordVersion = 9.
Every time I try to use the MAX command I get errors or the group by and I have tried every example I could find on the web but nothing seems to work.
Using MS SQL 2012.
Thanks,
Ken
Try the following query which attempts to solve your problem by ordering the returned rows by RecordVersion DESC and then SELECTs just the first row.
SELECT TOP 1
PriceCalendars.PriceProgramID,
PriceCalendars.EffectiveDateTime,
PriceSchedules.Price,
PriceSchedules.PLU,
items.Descr,
PriceSchedules.LastUpdate,
PriceSchedules.LastUpdatedBy,
PriceSchedules.RecordVersion,
PriceSchedules.PriceScheduleUniqueID
FROM
PriceCalendars
INNER JOIN PriceSchedules ON PriceCalendars.PriceProgramID = PriceSchedules.PriceProgramID
INNER JOIN items ON PriceSchedules.PLU = items.PLU
WHERE
(PriceSchedules.PLU = 'SLS10100103')
AND (PriceCalendars.EffectiveDateTime = '2016-03-22')
ORDER BY
RecordVersion DESC
All group by columns should be in select ,that's the rule of group by.How group by works is for every distinct combination of group by columns,arrange remaining columns into groups,so that any aggregation can be applied,in your case I am not sure what group by columns are unique with out test date.here is one version which use row number which gives you the output desired
Remember ,order by last updated date is the one which decides rows order and assign numbers
WITH CTE
AS
(
SELECT PriceCalendars.PriceProgramID,
PriceCalendars.EffectiveDateTime,
PriceSchedules.Price,
PriceSchedules.PLU,
items.Descr,
PriceSchedules.LastUpdate,
PriceSchedules.LastUpdatedBy,
PriceSchedules.RecordVersion,
PriceSchedules.PriceScheduleUniqueID,
ROW_NUMBER() OVER (PARTITION BY PriceSchedules.RecordVersion ORDER BY PriceSchedules.LastUpdatedBy) AS RN
FROM
PriceCalendars
INNER JOIN PriceSchedules ON PriceCalendars.PriceProgramID = PriceSchedules.PriceProgramID
INNER JOIN items ON PriceSchedules.PLU = items.PLU
WHERE
(PriceSchedules.PLU = 'SLS10100103')
AND (PriceCalendars.EffectiveDateTime = '2016-03-22')
)
SELECT * FROM CTE WHERE RN=1

Counting duplicate items in different order

Goal:
To know if we have purchased duplicate StockCodes or Stock Description more than once on difference purchase orders
So, if we purchase Part ABC on Purchase Order 1 and Purchase Order 2, it should return the result of
PurchaseOrders, Part#, Qty
Purchase Order1, Purchase Order2, ABC, 2
I just don't know how to pull the whole code together, more to the point, how do I know if it's occurred on more than 1 Purchase Order without scrolling through all the results , may also have to do with Multiple (Having Count) Statements as I only seem to be doing by StockCode
SELECT t1.PurchaseOrder,
t1.MStockCode,
Count(t1.MStockCode) AS SCCount,
t1.MStockDes,
Count(t1.MStockDes) AS DescCount
FROM PorMasterDetail t1
INNER JOIN PorMasterHdr t2
ON t1.PurchaseOrder = t2.PurchaseOrder
WHERE Year(t2.OrderEntryDate) = Year(Getdate())
AND Month(t2.OrderEntryDate) = Month(Getdate())
GROUP BY t1.PurchaseOrder,
t1.MStockCode,
t1.MStockDes
HAVING Count(t1.MStockCode) > 1
Using responses I came up with the following
select * from
(
SELECT COUNT(dbo.InvMaster.StockCode) AS Count, dbo.InvMaster.StockCode AS StockCodes,
dbo.PorMasterDetail.PurchaseOrder, dbo.PorMasterHdr.OrderEntryDate
FROM dbo.InvMaster INNER JOIN dbo.PorMasterDetail ON
dbo.InvMaster.StockCode = dbo.PorMasterDetail.MStockCode
INNER JOIN dbo.PorMasterHdr ON dbo.PorMasterDetail.PurchaseOrder = dbo.PorMasterHdr.PurchaseOrder
WHERE YEAR(dbo.PorMasterHdr.OrderEntryDate) = YEAR(GETDATE())
GROUP BY dbo.InvMaster.StockCode, dbo.InvMaster.StockCode,
dbo.PorMasterDetail.PurchaseOrder, dbo.PorMasterHdr.OrderEntryDate
) Count
Where Count.Count > 1
This returns the below , which is starting to be a bit more helpful
In result line 2,3,4 we can see the same stock code (*30044) ordered 3 times on different
purchase orders.
I guess the question is, is it possible to look at If something was ordered more than once within say a 30 day period.
Is this possible?
Count StockCodes PurchaseOrder OrderEntryDate
2 *12.0301.0021 322959 2014-09-08
2 *30044 320559 2014-01-21
8 *30044 321216 2014-03-26
4 *30044 321648 2014-05-08
5 *32317 321216 2014-03-26
4 *4F-130049/TEST 323353 2014-10-22
5 *650-1157/E 322112 2014-06-24
2 *650-1757 321226 2014-03-27
SELECT *
FROM
(
SELECT h.OrderEntryDate, d.*,
COUNT(*) OVER (PARTITION BY d.MStockCode) DupeCount
FROM
PorMasterHdr h
INNER JOIN PorMasterDetail d ON
d.PurchaseOrder = h.PurchaseOrder
WHERE
-- first day of current month
-- http://blog.sqlauthority.com/2007/05/13/sql-server-query-to-find-first-and-last-day-of-current-month/
h.OrderEntryDate >= CONVERT(VARCHAR(25), DATEADD(dd,-(DAY(GETDATE())-1),GETDATE()),101)
) dupes
WHERE
dupes.DupeCount > 1;
This should work if you're only deduping on stock code. I was a little unclear if you wanted to dedupe on both stock code and stock desc, or either stock code or stock desc.
Also I was unclear on your return columns because it almost looks like you're wanting to pivot the columns so that both purchase order numbers appear on the same line.

Resources