pulling data from a sql table that stores price history - sql

I have been trying to figure out how to pull data out of sql table that holds the history of price changes for items in inventory. Example of how the data is laid out is below:
Item No Date changed Price
1 11/20/2012 15
2 11/28/2012 25
1 12/1/2012 18
I am needing to pull the last entry for each item no so that i can find where prices have change by more than a certain percent. Once I get the information all worked out but i am not sure how to pull only the last two updates for each item. Any help will be greatly appreciated

Simple order it by date and retrieve exactly two rows per id.
SELECT Price FROM table WHERE id=2 ORDER BY date_changed DESC LIMIT 0,2
This are the two last price changes.

This is how i got it to work.
create table ##inventoryitems (ID INT Identity(1,1),itemno char(11));
insert into ##inventoryitems
select distinct itemno
from InventoryActPkgCostHist
where LocID=3
create table ##temptable (item# char(11),changedate datetime,price numeric(8,2));
DECLARE #Counter INT
SET #Counter = 1
while #Counter<=(select COUNT(*) from ##inventoryitems)
begin
insert into ##temptable
select top 2 i.itemno,i.ActPkgCostDate,i.ActPkgCost
from InventoryActPkgCostHist i join ##inventoryitesm temp on i.itemno= temp.itemno
where temp.id=#Counter and locidd=3
order by itemno,ActPkgCostDate desc
set #Counter=#Counter+1
end
Thank you for everyone's help

Related

SQL: Is there a way to sort a list of rows in a table numerically without adding a new column?

I want to order a list of rows in a table numerically without adding a new column to the table so that the column isn't altered. The new list I want to order numerically is based on some constraints I set on the data I selected.
Ex:
Number Title Year
1 Movie 2016
2 Movie 1983
3 Movie 2000
and so on.
I've tried using ORDER BY, but in order to do so there needs to be a new column to order it by. Can anyone help me with this? Thanks.
Edit #1: In case it's unclear, I want to add in the number 1, 2, 3 and so on (a number increasing numerically for each movie) without adding a new column to the table.
Edit #2: I'm using Toad as my database. Sorry for the lack of clarity, this is one of my first questions. Thanks!
In sqlserver you could use
select ROW_NUMBER() OVER() , title, year
from my_table
in mysql you could add row num this way
set #row = 0;
select #row := #row+1, title, year
from your_table
In Oracle you can use rownum
select rownum, title, year
from your_table
I found the answer, I just need to use COUNT(). Thanks for your contributions.
If the issue is that you do not want to add this column to the existing table have you considered importing the data into a temporary table and assigning some kind of index?
//Add this to drop the table in case it already exists
IF(OBJECT_ID('TEMPDB..#TEMP_TABLE') IS NOT NULL)
BEGIN
DROP TABLE #TEMP_TABLE
END
DECLARE #NUMBER INT = 0
SELECT TITLE, YEAR, #NUMBER AS [KEY] INTO #TEMP_TABLE FROM YOUR_TABLE
UPDATE #TEMP_TABLE
SET #NUMBER = #NUMBER + 1,
[KEY] = [KEY] + #NUMBER
SELECT * FROM #TEMP_TABLE

Add data to trigger from the last insert

I am faced with the following situation:
I created a trigger which reacts on insert to the third table. When I insert any data (for example 1 1 2), last number should be subtracted from the Amount of stock column from cell, which has necessary ID Product (as it's shown on picture). But how can I understand which row was the last added? I thought firstly to do it by select, but it seems impossible. And now I think that it's possible to do it with the help of cursor, but it doesn't seem as the best variant. Is there a better variant how can I do it?
Here's my code of trigger, but it only subtracts 1 from the 1st product each time, unfortunately:
CREATE TRIGGER AmountInsert ON Amount
AFTER INSERT
AS
BEGIN
UPDATE Product
SET Amount_On_Stock =
(SELECT Amount_On_Stock FROM Product
WHERE ID_Product = 1) - 1
WHERE ID_Product = 1
END
The first thing you need to understand is that in a trigger in SQL Server you are provided with an inserted pseudo-table and a deleted pseudo-table. You use these tables to determine what changes have occurred.
I think the following trigger accomplishes what you are looking for - the comments explain the logic.
CREATE TRIGGER dbo.AmountInsert ON dbo.Amount
AFTER INSERT
AS
BEGIN
set nocount on;
update P set
-- Adjust the stock level by the amount of the latest insert
Amount_On_Stock = coalesce(Amount_On_Stock) - I.Amount
from dbo.Product P
inner join (
-- We need to group by ID_Product in case the same product appears in the insert multiple times
select ID_Product, sum(Amount) Amount
from Inserted
group by ID_Product
-- No need to update is net change is zero
having sum(Amount) <> 0
) I
on I.ID_Product = P.ID_Product;
END

Filling one table using another table in SQL Server

I have two SQL tables as follows:
As you may note, the first table has a monthly frequency (date column), while the second table has a quarterly frequency. Here is what I would like to do:
For each issueid from table 1, I would like to look at the date, determine what is the previous end of quarter, and go fetch data from table 2 corresponding to that issue for that end of quarter, and insert it in the first table in the last two columns.
For example: take issueid 123456 and date 1/31/2014. The previous end of quarter is 12/31/2013. I would like to go to table 1, copy q_exp and q_act that correspond to that issueid and 12/31/2013, and paste it into the first table.
Of course, I would like to fill the entire first table and minimize manual inserts.
Any help would be appreciated! Thanks!
Try the following query
UPDATE issues
SET q_exp=(SELECT TOP 1 q.q_exp
FROM quarterlyTable q
WHERE q.issueid=i.issueid
AND q.[date]<=i.[date]
ORDER BY q.[date] DESC)
,q_act= (SELECT TOP 1 q.q_act
FROM quarterlyTable q
WHERE q.issueid=i.issueid
AND q.[date]<=i.[date]
ORDER BY q.[date] DESC)
FROM issues i

Update table increment field

using SQL server 2008.
Hi guys got this query here:
CREATE PROCEDURE [dbo].[GenerateNumbers]
#pg varchar(255)
AS
BEGIN
DECLARE #Counter as int
SET #Counter = 0
UPDATE dbo.paretoMain
SET #counter = NewPareto = #counter +1
WHERE PG = #pg
END
Works fine, only i want it to do this by a particular order of 1 column. basically order by column 1.
cant seem to figure out how though any ideas?
thanks guys!
EDIT:
Ok seems I've confused people so here goes.
3 columns in a table. 1 called "newpareto" 1 called "Sales" 1 called "part".
Sales has currency, part is varchar. Newpareto is blank.
I want to simply 100 numbers for 100 records (example), so when row1, Newpareto = 1.
This query i provided does this.
However. The 100 Records are not sorted. What i need is To somehow add order by in there to order by Sales column so that the top Sales (example £100.00) will be number 1 in the Newpareto column.
Any clearer?
I believe this may be what you are trying to do:
update paretoMain
set NewPareto=rn
from (select Sales, row_number() over(order by Sales desc) as rn from paretoMain) as x
where paretoMain.Sales=x.Sales

finding consecutive date pairs in SQL

I have a question here that looks a little like some of the ones that I found in search, but with solutions for slightly different problems and, importantly, ones that don't work in SQL 2000.
I have a very large table with a lot of redundant data that I am trying to reduce down to just the useful entries. It's a history table, and the way it works, if two entries are essentially duplicates and consecutive when sorted by date, the latter can be deleted. The data from the earlier entry will be used when historical data is requested from a date between the effective date of that entry and the next non-duplicate entry.
The data looks something like this:
id user_id effective_date important_value useless_value
1 1 1/3/2007 3 0
2 1 1/4/2007 3 1
3 1 1/6/2007 NULL 1
4 1 2/1/2007 3 0
5 2 1/5/2007 12 1
6 3 1/1/1899 7 0
With this sample set, we would consider two consecutive rows duplicates if the user_id and the important_value are the same. From this sample set, we would only delete row with id=2, preserving the information from 1-3-2007, showing that the important_value changed on 1-6-2007, and then showing the relevant change again on 2-1-2007.
My current approach is awkward and time-consuming, and I know there must be a better way. I wrote a script that uses a cursor to iterate through the user_id values (since that breaks the huge table up into manageable pieces), and creates a temp table of just the rows for that user. Then to get consecutive entries, it takes the temp table, joins it to itself on the condition that there are no other entries in the temp table with a date between the two dates. In the pseudocode below, UDF_SameOrNull is a function that returns 1 if the two values passed in are the same or if they are both NULL.
WHILE (##fetch_status <> -1)
BEGIN
SELECT * FROM History INTO #history WHERE user_id = #UserId
--return entries to delete
SELECT h2.id
INTO #delete_history_ids
FROM #history h1
JOIN #history h2 ON
h1.effective_date < h2.effective_date
AND dbo.UDF_SameOrNull(h1.important_value, h2.important_value)=1
WHERE NOT EXISTS (SELECT 1 FROM #history hx WHERE hx.effective_date > h1.effective_date and hx.effective_date < h2.effective_date)
DELETE h1
FROM History h1
JOIN #delete_history_ids dh ON
h1.id = dh.id
FETCH NEXT FROM UserCursor INTO #UserId
END
It also loops over the same set of duplicates until there are none, since taking out rows creates new consecutive pairs that are potentially dupes. I left that out for simplicity.
Unfortunately, I must use SQL Server 2000 for this task and I am pretty sure that it does not support ROW_NUMBER() for a more elegant way to find consecutive entries.
Thanks for reading. I apologize for any unnecessary backstory or errors in the pseudocode.
OK, I think I figured this one out, excellent question!
First, I made the assumption that the effective_date column will not be duplicated for a user_id. I think it can be modified to work if that is not the case - so let me know if we need to account for that.
The process basically takes the table of values and self-joins on equal user_id and important_value and prior effective_date. Then, we do 1 more self-join on user_id that effectively checks to see if the 2 joined records above are sequential by verifying that there is no effective_date record that occurs between those 2 records.
It's just a select statement for now - it should select all records that are to be deleted. So if you verify that it is returning the correct data, simply change the select * to delete tcheck.
Let me know if you have questions.
select
*
from
History tcheck
inner join History tprev
on tprev.[user_id] = tcheck.[user_id]
and tprev.important_value = tcheck.important_value
and tprev.effective_date < tcheck.effective_date
left join History checkbtwn
on tcheck.[user_id] = checkbtwn.[user_id]
and checkbtwn.effective_date < tcheck.effective_date
and checkbtwn.effective_date > tprev.effective_date
where
checkbtwn.[user_id] is null
OK guys, I did some thinking last night and I think I found the answer. I hope this helps someone else who has to match consecutive pairs in data and for some reason is also stuck in SQL Server 2000.
I was inspired by the other results that say to use ROW_NUMBER(), and I used a very similar approach, but with an identity column.
--create table with identity column
CREATE TABLE #history (
id int,
user_id int,
effective_date datetime,
important_value int,
useless_value int,
idx int IDENTITY(1,1)
)
--insert rows ordered by effective_date and now indexed in order
INSERT INTO #history
SELECT * FROM History
WHERE user_id = #user_id
ORDER BY effective_date
--get pairs where consecutive values match
SELECT *
FROM #history h1
JOIN #history h2 ON
h1.idx+1 = h2.idx
WHERE h1.important_value = h2.important_value
With this approach, I still have to iterate over the results until it returns nothing, but I can't think of any way around that and this approach is miles ahead of my last one.