Grouping in T-SQL - sql

Can you please advise how to make this special grouping in SQL
from this table
id FromDate ToDate UPC price IsGroupSpecial
3 2013-12-27 2013-12-30 6400000087492 315.00 1
2 2013-12-27 2013-12-31 6400000087492 405.00 0
Need to select all with min price but the id is not necessarily minimum - the id should be taken from that row where IsGroupSpecial= 0

I think this type of query is what you're looking for. If you're just looking for all records that have the minimum price than a group by clause is not necessary.
select *
from table
where price = (select min(price) from table))

If I understood correctly
select UPC, min(price), x.id
from table t1
cross apply (select id from table t2 where t2.IsGroupSpecial =0 and t1.UPC=t2.UPC) X
group by UPC, x.id

Related

totalling rows for distinct values in SQL

I haven't had much experience with SQL and it strikes me as a simple question, but after an hour of searching I still can't find an answer...
I have a table that I want to add up the totals for based on ID - e.g:
-------------
ID Quantity
1 30
2 11
1 4
1 3
2 17
3 16
.............
After summing the table should look something like this:
-------------
ID Quantity
1 37
2 28
3 16
I'm sure that I need to use the DISTINCT keyword and the SUM(..) function, but I can only get one total value for all unique value combinations in the table, and not separate ones like above. Help please :)
Select ID, Sum(Quantity) from YourTable
Group by ID
You can find here some resources to learn more about "Group by": http://www.w3schools.com/sql/sql_groupby.asp
SELECT ID, SUM(QUANTITY) FROM TABLE1 GROUP BY ID ORDER BY ID;
Select ID, Sum(Quantity) AS Quantity
from table1
Group by ID
Replace table1 with name of the table.
Just posting a complete answer that aliases the column and orders the results:
SELECT ID, SUM(Quantity) as [Quantity]
FROM TableName
GROUP BY ID
ORDER BY ID

Select particular not grouped column from grouped set

The topic might be a little bit unclear but I couldn't describe in a single sentence what I want to achieve.
Say I have a table that is (columns)
id INT PK
name VARCHAR
date DATE
I have a grouping select
select
name,
max(date)
from table
group by name
that gives me a name and the latest date.
What is the easiest way to join the id column to the current aggregated result set with the id value where the date was the maximum?
Let me explain what my goal is with an example:
The table is filled with the data as follows
id name date
1 david 2012-12-12
2 david 2013-12-02
3 patrick 2014-01-02
4 patrick 2012-11-11
and by my query I'd like to get the following result
id name date
2 david 2013-12-02
3 patrick 2014-01-02
Notice that all the records for name = 'david' are aggregated and the maximum date is selected. How to get the row id for this maximum date?
One option is to use ROW_NUMBER():
SELECT id, name, date
FROM (
SELECT id, name, date,
row_number() over (partition by name order by date desc) rn
FROM yourtable
) t
WHERE rn = 1
SQL Fiddle Demo
Another option is to join the table back to itself using the MAX() aggregate. This option could potentially result in ties if multiple id/name combinations share the same max date:
SELECT t.id, t.name, t.date
FROM yourtable t
JOIN (SELECT name, max(date) maxdate
FROM yourtable
GROUP BY name) t2 on t.name = t2.name AND t.date = t2.maxdate
More Fiddle

Get a single value where the latest date

I need to get the latest price of an item (as part of a larger select statement) and I can't quite figure it out.
Table:
ITEMID DATE SALEPRICE
1 1/1/2014 10
1 2/2/2014 20
2 3/3/2014 15
2 4/4/2014 13
I need the output of the select to be '20' when looking for item 1 and '13' when looking for item 2 as per the above example.
I am using Oracle SQL
The most readable/understandable SQL (in my opinion) would be this:
select salesprice from `table` t
where t.date =
(
select max(date) from `table` t2 where t2.itemid = t.itemid
)
and t.itemid = 1 -- change item id here;
assuming your table's name is table and you only have one price per day and item (else the where condition would match more than one row per item). Alternatively, the subselect could be written as a self-join (should not make a difference in performance).
I'm not sure about the OVER/PARTITION used by the other answers. Maybe they could be optimized to better performance depending on the DBMS.
Maybe something like this:
Test data
DECLARE #tbl TABLE(ITEMID int,DATE DATETIME,SALEPRICE INT)
INSERT INTO #tbl
VALUES
(1,'1/1/2014',10),
(1,'2/2/2014',20),
(2,'3/3/2014',15),
(2,'4/4/2014',13)
Query
;WITH CTE
AS
(
SELECT
ROW_NUMBER() OVER(PARTITION BY ITEMID ORDER BY [DATE] DESC) AS rowNbr,
tbl.*
FROM
#tbl AS tbl
)
SELECT
*
FROM
CTE
WHERE CTE.rowNbr=1
Try this!
In sql-server may also work in Oracle sql
select * from
(
select *,rn=row_number()over(partition by ITEMID order by DATE desc) from table
)x
where x.rn=1
You need Row_number() to allocate a number to all records which is partition by ITEMID so each group will get a RN,then as you are ordering by date desc to get Latest record
SEE DEMO

Get adjacent fields with GROUP BY / MAX

This has probably been asked many times but I can't find a solution because I don't know how to phrase this question.
[product] [shop] [price] [date]
Pizza Shop1 10 2014-05-10
Pizza Shop2 12 2014-05-04
Snow Shop1 101 2014-05-02
Snow Shop3 93 2014-05-11
I wish to query this table and get the price of the last added product:
[product] [shop] [price] [date]
Pizza Shop1 10 2014-05-10
Snow Shop3 93 2014-05-11
An obviously wrong syntax:
SELECT
product,
shop WHERE MAX(date),
price WHERE MAX(date),
MAX(date)
FROM myTable
GROUP BY product
This query is already a part of a subquery so I want the best possible performing solution.
Using ROW_NUMBER() you can split the records in to partitions for each product, and assign each a row number, starting with 1 for the newest record for a partition (product).
Then you just select all the records with a row number of 1, for each product.
WITH
sequenced AS
(
SELECT
myTable.*,
ROW_NUMBER() OVER (PARTITION BY [product] ORDER BY [date] DESC) AS product_date_ordinal
FROM
myTable
)
SELECT
*
FROM
sequenced
WHERE
product_date_ordinal = 1
This assumes SQL SERVER 2005 onwards, and you should have an index on product, date DESC for best performance.
You can try this aswell. Using join with subquery to filter your table, not as good as first answer I guess, but easier to read and understand:
SELECT Table.*
FROM Table
RIGHT JOIN
(
SELECT product, max(date) AS date FROM Table
GROUP BY product
) AS Filter
ON Filter.product = Table.product AND Filter.date = Table.date
Just replace "Table" with the name of your table.

SQL. Is there any efficient way to find second lowest value?

I have the following table:
ItemID Price
1 10
2 20
3 12
4 10
5 11
I need to find the second lowest price. So far, I have a query that works, but i am not sure it is the most efficient query:
select min(price)
from table
where itemid not in
(select itemid
from table
where price=
(select min(price)
from table));
What if I have to find third OR fourth minimum price? I am not even mentioning other attributes and conditions... Is there any more efficient way to do this?
PS: note that minimum is not a unique value. For example, items 1 and 4 are both minimums. Simple ordering won't do.
SELECT MIN( price )
FROM table
WHERE price > ( SELECT MIN( price )
FROM table )
select price from table where price in (
select
distinct price
from
(select t.price,rownumber() over () as rownum from table t) as x
where x.rownum = 2 --or 3, 4, 5, etc
)
Not sure if this would be the fastest, but it would make it easier to select the second, third, etc... Just change the TOP value.
UPDATED
SELECT MIN(price)
FROM table
WHERE price NOT IN (SELECT DISTINCT TOP 1 price FROM table ORDER BY price)
To find out second minimum salary of an employee, you can use following:
select min(salary)
from table
where salary > (select min(salary) from table);
This is a good answer:
SELECT MIN( price )
FROM table
WHERE price > ( SELECT MIN( price )
FROM table )
Make sure when you do this that there is only 1 row in the subquery! (the part in brackets at the end).
For example if you want to use GROUP BY you will have to define even further using:
SELECT MIN( price )
FROM table te1
WHERE price > ( SELECT MIN( price )
FROM table te2 WHERE te1.brand = te2.brand)
GROUP BY brand
Because GROUP BY will give you multiple rows, otherwise you will get the error:
SQL Error [21000]: ERROR: more than one row returned by a subquery used as an expression
I guess a simplest way to do is using offset-fetch filter from standard sql, distinct is not necessary if you don't have repeat values in your column.
select distinct(price) from table
order by price
offset 1 row fetch first 1 row only;
no need to write complex subqueries....
In amazon redshift use limit-fetch instead for ex...
Select distinct(price) from table
order by price
limit 1
offset 1;
You can either use one of the following:-
select min(your_field) from your_table where your_field NOT IN (select distinct TOP 1 your_field from your_table ORDER BY your_field DESC)
OR
select top 1 ColumnName from TableName where ColumnName not in (select top 1 ColumnName from TableName order by ColumnName asc)
I think you can find the second minimum using LIMIT and ORDER BY
select max(price) as minimum from (select distinct(price) from tableName order by price asc limit 2 ) --or 3, 4, 5, etc
if you want to find third or fourth minimum and so on... you can find out by changing minimum number in limit. you can find using this statement.
You can use RANK functions,
it may seem complex query but similar results like other answers can be achieved with the same,
WITH Temp_table AS (SELECT ITEM_ID,PRICE,RANK() OVER (ORDER BY PRICE) AS
Rnk
FROM YOUR_TABLE_NAME)
SELECT ITEM_ID FROM Temp_table
WHERE Rnk=2;
Maybe u can check the min value first and then place a not or greater than the operator. This will eliminate the usage of a subquery but will require a two-step process
select min(price)
from table
where min(price) <> -- "the min price you previously got"