I know this is simple for most of you!
I have an Invoices table like so:
+-----------+------------+------+-------+
| InvoiceID | Date | Item | Price |
+-----------+------------+------+-------+
| 1 | 15/04/2014 | A | 12 |
| 2 | 20/04/2014 | A | 20 |
| 3 | 20/04/2014 | A | 27 |
| 4 | 20/04/2014 | B | 29 |
| 5 | 28/04/2014 | C | 16 |
| 6 | 28/04/2014 | B | 11 |
+-----------+------------+------+-------+
I would like to retrieve the Price against the Last Invoice ID for each Item, so:
+------+-----------+
| Item | LastPrice |
+------+-----------+
| A | 27 |
| B | 11 |
| C | 16 |
+------+-----------+
What is the most efficient way of doing this? I'm using SQL Server 2008
Many thanks in advance to any help received.
with cte as (
select *, row_number() over (partition by Item order by date desc) as r
from dbo.YourTable
)
select * from cte where r = 1
This may do your work :
SELECT Item,
Price AS 'LastPrice'
FROM MyTable
WHERE InvoiceId IN (SELECT Max(InvoiceId)
FROM MyTable
GROUP BY Item)
Related
I have the following two tables in SQL server:
Product:
SELECT Id, Name From Product
x------x--------------------x
| Id | Name |
x------x--------------------x
| 1 | A |
| 2 | B |
| 3 | C |
x------x--------------------x
Order:
SELECT Id, Order_Date, QTY From Order
x------x--------------------x-------x
| Id | Order_Date | QTY |
x------x--------------------x-------x
| 1 | 2014-01-13 | 10 |
| 1 | 2014-01-11 | 15 |
| 1 | 2014-01-12 | 20 |
| 2 | 2014-01-06 | 30 |
| 2 | 2014-01-08 | 40 |
x------x--------------------x-------x
I would like to get a table which contains list of all products and if there is any order placed for the product.
Example:
x------x--------------------x
| Id | Has_Order |
x------x--------------------x
| 1 | 1 |
| 2 | 1 |
| 3 | 0 |
x------x--------------------x
I tried left outer join but it includes all the rows from Order table. What is the most efficient way to write this SQL query?
You can use exists in a subquery:
select p.*,
(case when exists (select 1 from orders o where o.id = p.id)
then 1 else 0
end) as order_exists_flag
from products p;
For performance, you want an index on orders(id). I would expect this to be the fastest approach.
Just another option to consider
Select ID
,Has_Order = max(Flg)
From (
Select ID,Flg = 0 From [Product]
Union All
Select Distinct ID,Flg = 1 From [Order]
) src
Group By ID
Here is my table A.
| Id | GroupId | StoreId | Amount |
| 1 | 20 | 7 | 15000 |
| 2 | 20 | 7 | 1230 |
| 3 | 20 | 7 | 14230 |
| 4 | 20 | 7 | 9540 |
| 5 | 20 | 7 | 24230 |
| 6 | 20 | 7 | 1230 |
| 7 | 20 | 7 | 1230 |
Here is my table B.
| Id | GroupId | StoreId | Credit |
| 12 | 20 | 7 | 1230 |
| 14 | 20 | 7 | 15000 |
| 15 | 20 | 7 | 14230 |
| 16 | 20 | 7 | 1230 |
| 17 | 20 | 7 | 7004 |
| 18 | 20 | 7 | 65523 |
I want to get this result without getting duplicate Id of both table.
I need to get the Id of table B and A where the Amount = Credit.
| A.ID | B.ID | Amount |
| 1 | 14 | 15000 |
| 2 | 12 | 1230 |
| 3 | 15 | 14230 |
| 4 | null | 9540 |
| 5 | null | 24230 |
| 6 | 16 | 1230 |
| 7 | null | 1230 |
My problem is when I have 2 or more same Amount in table A, I get duplicate ID of table B. which should be null. Please help me. Thank you.
I think you want a left join. But this is tricky because you have duplicate amounts, but you only want one to match. The solution is to use row_number():
select . . .
from (select a.*, row_number() over (partition by amount order by id) as seqnum
from a
) a left join
(select b.*, row_number() over (partition by credit order by id) as seqnum
from b
)b
on a.amount = b.credit and a.seqnum = b.seqnum;
Another approach, I think simplier and shorter :)
select ID [A.ID],
(select top 1 ID from TABLE_B where Credit = A.Amount) [B.ID],
Amount
from TABLE_A [A]
How can I compare 2 tables with the same rows, but different data?
The tables are something like this:
1. Table price_old:
|-----------------------|
| id | price1 | price2 |
|-----------------------|
| 1 | 12 | 12 |
|-----------------------|
| 2 | 12 | 55 |
------------------------|
| 3 | 12 | 40 |
-------------------------
The tables are something like this:
2. Table price_old:
|-----------------------|
| id | price1 | price2 |
|-----------------------|
| 1 | 12 | 12 |
|-----------------------|
| 2 | 13 | 40 |
------------------------|
| 3 | 10 | 40 |
-------------------------
The Result should look like this:
3. Table Result:
|----------------------------------------------------------|
| id | price1_old | price1_new | price2_old | price2_new |
|----------------------------------------------------------|
| 2 | 12 | 13 | 55 | 40 |
|----------------------------------------------------------|
| 3 | 13 | 10 | 40 | 40 |
Try this, joining on the id and filtering out occurrences where at least one price is different:
SELECT
old.id,
old.price1 as price1_old,
old.price2 as price2_old,
new.price1 as price1_new,
new.price2 as price2_new
FROM price_old as old
LEFT JOIN price_new as new on old.id=new.id
WHERE old.price1<>new.price1
OR old.price2<>new.price2
This is might be an approach:
SELECT 'TableName' AS `set`, r.*
FROM robot r
WHERE ROW(r.col1, r.col2, …) NOT IN
(
SELECT *
FROM TableName2
)
UNION ALL
SELECT 'TableName2' AS `set`, t.*
FROM tbd_robot t
WHERE ROW(t.col1, t.col2, …) NOT IN
(
SELECT *
FROM TableName1
)
I have been trying to get this to work with some row_number, group by, top, sort of things, but I am missing some fundamental concept. I have a table like so:
+-------+-------+-------+
| name | ord | f_id |
+-------+-------+-------+
| a | 1 | 2 |
| b | 5 | 2 |
| c | 6 | 2 |
| d | 2 | 1 |
| e | 4 | 1 |
| a | 2 | 3 |
| c | 50 | 4 |
+-------+-------+-------+
And my desired output would be:
+-------+---------+--------+-------+
| f_id | ord_n | ord | name |
+-------+---------+--------+-------+
| 2 | 1 | 1 | a |
| 2 | 2 | 5 | b |
| 1 | 1 | 2 | d |
| 1 | 2 | 4 | e |
| 3 | 1 | 2 | a |
| 4 | 1 | 50 | c |
+-------+---------+--------+-------+
Where data is ordered by the ord value, and only up to two results per f_id. Should I be working on a Stored Procedure for this or can I just do it with SQL? I have experimented with some select TOP subqueries, but nothing has even come close..
Here are some statements to create the test table:
create table help(name varchar(255),ord tinyint,f_id tinyint);
insert into help values
('a',1,2),
('b',5,2),
('c',6,2),
('d',2,1),
('e',4,1),
('a',2,3),
('c',50,4);
You may use Rank or DENSE_RANK functions.
select A.name, A.ord_n, A.ord , A.f_id from
(
select
RANK() OVER (partition by f_id ORDER BY ord asc) AS "Rank",
ROW_NUMBER() OVER (partition by f_id ORDER BY ord asc) AS "ord_n",
help.*
from help
) A where A.rank <= 2
Sqlfiddle demo
I've been struggling with the following SQL query.
My resultset is now:
| Id | Customer | Sales |
| 1 | 1 | 10 |
| 2 | 1 | 20 |
| 3 | 2 | 30 |
| 4 | 2 | 40 |
What I'd like to do is to add additional column that shows the smallest sale for that customer:
| Id | Customer | Sales | SmallestSale |
| 1 | 1 | 10 | 10 |
| 2 | 1 | 20 | 10 |
| 3 | 2 | 30 | 30 |
| 4 | 2 | 40 | 30 |
As the select query to get those three columns is now rather complex I'd like to avoid subqueries.
Any ideas?
Mika
Assuming your RDBMS supports windowed aggregates
SELECT Id,
Customer,
Sales,
MIN(Sales) OVER (PARTITION BY Customer) AS SmallestSale
FROM YourTable
select s.Id, s.Customer, s.Sales, sm.SmallestSale
from Sales s
inner join (
select Customer, min(sales) as SmallestSale
from Sales
group by Customer
) sm on s.Customer = sm.Customer