Combining SQL Where Clauses - sql

This is my code
SELECT sum(qty) as "sumqty", shipdate, groupnumber
from test
where (shipdate = #5/30/2014# and groupnumber = "A30") OR ( shipdate #5/31/2014# and groupnumber ="A31")
group by shipdate, groupnumber
order by sum(qty) desc;
Is there a way to shorten the where clause? Because I want to add more shipdate and groupnumber combinations.

If I understand you correctly, your question isn't about your current query, but about scaling the query to include more combinations of shipdate and groupnumber. Obviously, if you only have a few more such combinations to add, then it's not a big deal to just add them. However, if you need to add many more such combinations, then consider using a join.
You haven't said which database server and version you're using, so I'll have to try to be general.
Create a temporary table with shipdate and groupnumber columns
Use a WHERE EXISTS clause:
SELECT sum(qty) as "sumqty", shipdate, groupnumber
from test
where exists (
select shipdate,groupnumber
from #Temp_Table as tt
where tt.shipdate = test.shipdate and tt.groupnumber = test.groupnumber)
group by shipdate, groupnumber
order by sum(qty) desc;

Remove all occurrences of "test." prefix because there is a single table in the query.
You can use short alias names of selected fields.

I would create a stored procedure, and then pass the different shipdates and group numbers into that, the query would then become
SELECT sum(qty) as "sumqty", shipdate, groupnumber
from test
where (shipdate = #ShipDate and groupnumber = #GroupNumber)
group by shipdate, groupnumber
order by sum(qty) desc;
If you need to get a result set for multiple sets of ShipDate/GroupNumber combinations you can just UNION or UNION ALL the results, depending on your requirements.
Please note this is not the only way of solving this problem, if you find that you need to query for lots of combinations a common table expression or even dynamic SQL might perform better

Related

SQL: Selecting multiple fields with one unique field based on most recent date

I'm attempting to write an SQL statement to select a unique part number based on the most recent date.
If I have just the two fields PartNo and ReceiveDate I could do:
"SELECT PartNo, Max(ReceiveDate) FROM Table GROUP BY PartNo;"
and this would return the unique PartNo and the most recent date.
The problem is that I also want to include the fields VendorName and Qty (But I just want PartNo to be unique). I've tried:
"SELECT PartNo, VendorName, Qty, Max(ReceiveDate) FROM Table GROUP BY PartNo;"
and
"SELECT PartNo, VendorName, Qty, Max(ReceiveDate) FROM Table GROUP BY PartNo, VendorName, Qty;"
I understand why these two SELECT statements are wrong, the first one doesn't run since VendorName and Qty aren't in the GROUP BY clause or part of an aggregate function, and in the second one it selects a unique record based on PartNo AND VendorName AND Qty, not just PartNo.
If someone could help me write the correct SQL statement that would be must appreciated. I'm using Microsoft Access which uses Jet SQL which is very similar to T-SQL.
I would suggest a correlated subquery:
SELECT t.*
FROM Table as t
WHERE t.ReceiveDate = (SELECT MAX(t2.ReceiveDate)
FROM Table as t2
WHERE t2.PartNo = t.PartNo
);
In particular, this can take advantage of an index on (PartNo, ReceiveDate).
If you mean, you don't care from which row Vendorname and Qty comes from (per partNo), then you can simply make them some aggregate function:
SELECT PartNo,
max(VendorName) as VendorName,
max(Qty) as Qty,
Max(ReceiveDate) as ReceiveDate
FROM [Table]
GROUP BY PartNo;
Probably a better approach would be to get those VendorName and Qty from the row with the last receive date (I assume that grouping return 1 date per PartNum):
select t.PartNo, t.VendorName, t.Qty, tmp.LastDate as ReceiveDate
from (SELECT PartNo, Max(ReceiveDate) as lastDate
FROM [Table]
GROUP BY PartNo) tmp
inner join [Table] t on t.PartNo = tmp.PartNo
where t.ReceiveDate = tmp.lastDate;
And I assume, no one really would name a table [Table].
Try to use crosstab query:
SELECT DISTINCT X.PartNo,X.MaxDate,Y.VendorName,Y.Qty FROM
(SELECT PartNo, Max(ReceiveDate)MaxDate FROM Table GROUP BY PartNo)X,
(SELECT PartNo, VendorName, Qty From Table)Y
WHERE X.PartNo=Y.PartNo

Redshift: Alternative to filter 1st row after "row_number() partition by", with better performance

In this example, I try to get the datetime and product name of the 1st order from each customer.
My query looks like this:
select * from(
select customerid,
orderdatetime,
productname,
row_number() over (partition by customerid order by orderdatetime) rn
from t
) where rn=1
In table t, customerid+orderdatetime can serve as the primary key, while productname is free text characters. There are huge number of customers, and each customer made significant number of orders.
I feel that in this query, much calculation is wasted in order by, because I want only the earliest (minimum). Is there really such waste? Is there alternative way to get the result, which is faster?
I'm using Amazon Redshift‎.
you can try by using corelated subquery, as customer id and orderdatetime is primary key
so it may help to get better performance
select t.* from your_table t
where orderdatetime = (select min(orderdatetime) from your_table t1
where t1.customerid=t.customerid
)

SQL Query to retrieve Count

With my SQL getting rusty I'm trying hard to get this working.
I have a table with multiple entries as shown in the attached image.
I need to write a query so that it returns me the count of the number of entries. i.e, 7 in this case. which is a distinct combination of MainID, ItemID, DeviceID, and ChannelID
Thanks for your help!!
Try the following:
Select
Count(*)
From
(
Select
Distinct
MainID,
ItemID,
DeviceID,
ChannelID
From
yourtable
)X;
Just use distinct as you are looking for distinct combination
ie
select distinct MainID, ItemID, DeviceID, ChannelID from Yourtable
ROW_NUMBER()
there may have many other solutions.
But to speed-up, your query's best use is to Use ROW_NUMBER().
Sample code:
select
MainID,
ItemID,
DeviceID,
ChannelID,
ROW_NUMBER() OVER(ORDER BY MainID,ItemID,DeviceID,ChannelID) as COUNT_VAR
from Your_table;
It is faster than GROUP BY query because GROUP BY uses run_time generation of sequence number where ROW_NUMBER() uses SQL Server defined default indexes.
Hope this will help you
IF OBJECT_ID('tempdb..#T') IS NOT NULL
BEGIN
DROP TABLE #T
END
CREATE TABLE #T (
MainId INT
,ItemId INT
,DeviceId INT
,ChannelId INT
)
INSERT INTO #T VALUES (1,1,2,1),(1,1,2,2),(1,1,2,3),(1,1,22,0),(1,2,1,1),(1,2,1,2)
,(1,2,1,3),(1,2,2,1),(1,2,2,2),(1,2,2,3),(1,2,3,1),(1,2,3,2),(1,2,3,3),(1,2,4,1)
,(1,2,4,2),(1,2,4,3),(1,2,5,1),(1,2,5,2),(1,2,5,3)
SELECT MainId, ItemId, DeviceId, COUNT(*) as RecordCount
FROM
#T
GROUP BY
MainId, ItemId, DeviceId
SELECT DISTINCT MainId, ItemId, DeviceId
FROM
#T
SELECT *, DENSE_RANK() OVER (ORDER BY MainId, ItemId, DeviceId) as GroupNumber
FROM
#t
As I have previously stated the reason you are having difficulty is that you are including ChannelId into your query and that of the other answers. If ChannelId is included it means that there will be more than 7 Distinct combinations of records. And no my original query did not return more than 7 records it returned only 7 records and the count of how many records of that combination of columns.
I have updated with 3 examples including sample data, which I urge you to do for people next time as you are asking us for help so make it easy provide DML statements rather than an image of your test case!
Example 1 simply adds the group by columns into my original query so you could see what I was talking about and was a little oversight.
Example 2 is the distinct which is basically the same as #1.
Example 3 if you want all of the other data like you have specified in other comments you would actually want to use a windowed function if your DBMS supports it, but of course this doesn't translate perfectly to linq. But you would need to use DENSE_RANK() to get the grouping the way you want it.

SQL Group by with min and corresponding values in a single query

Can I write a single query returning group by with min values and corresponding values in an optimized manner? Currently we are using multiple queries for the same.
eg:
A table has product category, product name, product id and price. I want to return the product type with min(price) but also product name and product id as well. This is in SQL 2008. Product name and product id can be duplicate
Edit 1: Added input and output for clarity
The first note is that SQL is a declarative language; it declares a functional requirement, not how that requirement will be solved (the SQL is 'compiled' in to an explain/execution plan, based on stats, indexes, hints, etc, etc, and then that's what is executed.).
That said, some SQL expressions are more costly than others. Your case has a simple solution using analytic functions (aka windowed functions) that has a low cost due to scanning the table (or appropriate index) only once.
SELECT
*
FROM
(
SELECT
*,
RANK() OVER (PARTITION BY category ORDER BY price) AS category_price_rank
FROM
your_table
)
ranked_your_table
WHERE
category_price_rank = 1
SELECT * FROM (
SELECT ProductCatg, ProductName, ProductID, MIN(PRICE), DateOrdered
FROM YOUR_TABLE
GROUP BY ProductCatg, ProductName, ProductID, DateOrdered ) A
WHERE A.PRICE = (SELECT MIN(PRICE)
FROM YOUR_TABLE
WHERE ProductCatg = A.ProductCatg AND ProductName = A.ProductName )

SQL Custom Grouping and Selection Query

I recently asked this question here and got some great answers!
Custom SQL GROUP BY Clause
However, it turns out I provided the wrong requirements for my problem. Sorry guys!
Sooooo. What I need to select is:
Distinct values in the Column 'PartNumbers', however:
-->For EACH unique PartNumber, I want to select the specific ROW from that table that has the MAX VALUE of the 'PO' Column for that particular part number.
-->Also, to make life more difficult, I want to exclude the ANY of the PartNumbers who have ANY VALUE in the Column 'Receipt'
You guys have been a great help! Much appreciated everyone!
EDIT:
Table Name: Log
Columns: ID, Supplier, PartNumber, PO, Quantity, DateReceived
Note: only the ID column is unique.
Using CTE:
with TableWithRowNumber as
(select
*,
row_number() over (partition by PartNumber order by PO desc) as RowNo
from MyTable)
select * from TableWithRowNumber
where RowNo = 1
and PartNumber not in
(select distinct PartNumber from MyTable where Receipt is not null)