dbTalk Databases Forums  

Help needed to write a qury

comp.databases.ms-sqlserver comp.databases.ms-sqlserver


Discuss Help needed to write a qury in the comp.databases.ms-sqlserver forum.



Reply
 
Thread Tools Display Modes
  #11  
Old   
Lennart Jonsson
 
Posts: n/a

Default Re: Help needed to write a qury - 04-25-2011 , 10:44 AM






2011-04-24 21:51, Erland Sommarskog skrev:
[...]
Quote:
Fred who posted the other solution should take notice. The row_number
function, added in SQL 2005, is much more efficient in numbering the rows
than using a subquery.

Any rumors on lead and/or lag analytical functions in sqlserver?


/Lennart

Reply With Quote
  #12  
Old   
Fred.
 
Posts: n/a

Default Re: Help needed to write a qury - 04-25-2011 , 01:41 PM






On Apr 25, 9:31*am, Erland Sommarskog <esq... (AT) sommarskog (DOT) se> wrote:
Quote:
Erland Sommarskog (esq... (AT) sommarskog (DOT) se) writes:
Thanks for the sample data!

I see that I had forgot the join condition on EmpId - without the queryis
kind of meaningless.

The principle is simple: number the rows, and then make a self-join on
the row number with the next number.

Pressed Send to quickly! Here is the query:

WITH numbered AS (
* *SELECT EmpId, EmpName, DepartmentID, AllocationDate,
* * * * * rowno = row_number() OVER(PARTITION BY EmpId
* * * * * * * * * * * * * * * * * * ORDER BY AllocationDate)
* *FROM * EmployeeDept
)
SELECT a.EmpId, a.EmpName, a.DepartmentID AS OldDeptID,
* * * *b.DepartmentID AS NewDeptID, a.AllocationDate,
* * * *b.AllocationDate AS TransferDate
FROM * numbered a
JOIN * numbered b ON b.rowno = a.rowno +1
* * * * * * * * *AND b.EmpId = a.EmpId
ORDER *BY a.EmpId, a.rowno

--
Erland Sommarskog, SQL Server MVP, esq... (AT) sommarskog (DOT) se

Links for SQL Server Books Online:
SQL 2008:http://msdn.microsoft.com/en-us/sqlserver/cc514207.aspx
SQL 2005:http://msdn.microsoft.com/en-us/sqlserver/bb895970.aspx
Let's see if I understand what is going on here.

The WITH clause works in a manner similar to a derived table, but sets
up the syntax so that it can be referenced more than once. In this
instance it allows the table to joined to itself rather than a second
derivation of itself as would happen using the derived table syntax.

The OVER construct (just what is the syntax term?) specifies that row
numbering restarts for each new value of the field specified in
PARTITION BY, with the rows arranged within each partition as
specified in ORDER BY.

Do you know if the engine optimizes by indexing the WITH table on the
PARTTION field and the field receiveing row_number()?

Thanks,

Fred.

Reply With Quote
  #13  
Old   
Erland Sommarskog
 
Posts: n/a

Default Re: Help needed to write a qury - 04-25-2011 , 04:18 PM



Fred. (ghrno-google (AT) yahoo (DOT) com) writes:
Quote:
The WITH clause works in a manner similar to a derived table, but sets
up the syntax so that it can be referenced more than once. In this
instance it allows the table to joined to itself rather than a second
derivation of itself as would happen using the derived table syntax.
Correct. This is known as a CTE, Common Table Expression.

Quote:
The OVER construct (just what is the syntax term?) specifies that row
numbering restarts for each new value of the field specified in
PARTITION BY, with the rows arranged within each partition as
specified in ORDER BY.
Correct. It's called the OVER clause.

Quote:
Do you know if the engine optimizes by indexing the WITH table on the
PARTTION field and the field receiveing row_number()?
The CTE is purely logical. Some products are able to materialize the CTE as
optimisation, but SQL Server is not. Thus, in some cases it can be better
to use a temp table to hold the numbering.

Lennart mention LEAD and LAG. They are also subclauses within OVER. They
are not available in SQL Server currently, but in products that have LAG and
LEAD, this can be written as a straight query without a self-join.


--
Erland Sommarskog, SQL Server MVP, esquel (AT) sommarskog (DOT) se

Links for SQL Server Books Online:
SQL 2008: http://msdn.microsoft.com/en-us/sqlserver/cc514207.aspx
SQL 2005: http://msdn.microsoft.com/en-us/sqlserver/bb895970.aspx

Reply With Quote
  #14  
Old   
Dinesh
 
Posts: n/a

Default Re: Help needed to write a qury - 04-26-2011 , 03:58 AM



On Apr 26, 2:18*am, Erland Sommarskog <esq... (AT) sommarskog (DOT) se> wrote:
Quote:
Fred. (ghrno-goo... (AT) yahoo (DOT) com) writes:
The WITH clause works in a manner similar to a derived table, but sets
up the syntax so that it can be referenced more than once. *In this
instance it allows the table to joined to itself rather than a second
derivation of itself as would happen using the derived table syntax.

Correct. This is known as a CTE, Common Table Expression.

The OVER construct (just what is the syntax term?) specifies that row
numbering restarts for each new value of the field specified in
PARTITION BY, with the rows arranged within each partition as
specified in ORDER BY.

Correct. It's called the OVER clause.

Do you know if the engine optimizes by indexing the WITH table on the
PARTTION field and the field receiveing row_number()?

The CTE is purely logical. Some products are able to materialize the CTE as
optimisation, but SQL Server is not. Thus, in some cases it can be better
to use a temp table to hold the numbering.

Lennart mention LEAD and LAG. They are also subclauses within OVER. They
are not available in SQL Server currently, but in products that have LAG and
LEAD, this can be written as a straight query without a self-join.

--
Erland Sommarskog, SQL Server MVP, esq... (AT) sommarskog (DOT) se

Links for SQL Server Books Online:
SQL 2008:http://msdn.microsoft.com/en-us/sqlserver/cc514207.aspx
SQL 2005:http://msdn.microsoft.com/en-us/sqlserver/bb895970.aspx
Thanks a lot for all.

Reply With Quote
  #15  
Old   
Erland Sommarskog
 
Posts: n/a

Default Re: Help needed to write a qury - 05-24-2011 , 05:01 PM



Lennart Jonsson (erik.lennart.jonsson (AT) gmail (DOT) com) writes:
Quote:
Any rumors on lead and/or lag analytical functions in sqlserver?
I have not watched this video in detail, but Microsoft reportedly demoed
new window functions at TechEd:

http://channel9.msdn.com/Events/Tech...ca/2011/DBI310

It's certainly a big uplift for us on SQL Server!


--
Erland Sommarskog, SQL Server MVP, esquel (AT) sommarskog (DOT) se

Links for SQL Server Books Online:
SQL 2008: http://msdn.microsoft.com/en-us/sqlserver/cc514207.aspx
SQL 2005: http://msdn.microsoft.com/en-us/sqlserver/bb895970.aspx

Reply With Quote
  #16  
Old   
Lennart Jonsson
 
Posts: n/a

Default Re: Help needed to write a qury - 05-25-2011 , 02:15 PM



On 2011-05-25 00:01, Erland Sommarskog wrote:
Quote:
Lennart Jonsson (erik.lennart.jonsson (AT) gmail (DOT) com) writes:
Any rumors on lead and/or lag analytical functions in sqlserver?

I have not watched this video in detail, but Microsoft reportedly demoed
new window functions at TechEd:

http://channel9.msdn.com/Events/Tech...ca/2011/DBI310

Thanks for the link Erland. I've only looked at the first 20 minutes so
far, but in my opinion it's a very good presentation. I like the way
that he approaches the subject.

/Lennart

Reply With Quote
  #17  
Old   
--CELKO--
 
Posts: n/a

Default Re: Help needed to write a qury - 05-26-2011 , 08:19 AM



Please post real DDL. Learn to use ISO-11179 rules for the data
element names, avoid needless dialect and use ISO-8601 temporal
formats, codes and so forth. Based on the vague narrative you did
post, the design is wrong.

Let me use a history table for price changes. The fact is that a
price had duration. This is the nature of time and other continuums.
So a basic history table looks like this in SQL/PSM

CREATE TABLE PriceHistory
(upc CHAR(13) NOT NULL -- industry standard
REFERENCES Inventory(upc),
price_prev_date DATE NOT NULL,
price_start_date DATE DEFAULT CURRENT_DATE NOT NULL,
price_end_date DATE, -- null means current price
CHECK(price_start_date < price_end_date),
CHECK (price_start_date = price_prev_date + INTERVAL 1 DAY), --
prevents gaps
PRIMARY KEY (upc, price_start_date),
item_price DECIMAL (12,4) NOT NULL
CHECK (item_price > 0.0000),
etc.);

You use a BETWEEN predicate to get the appropriate price. You can
enforce the "one null per item" with a trigger but techically this
should work:

CHECK (COUNT(*) OVER (PARTITION BY upc)
= COUNT(price_end_date) OVER (PARTITION BY upc) +1)

SELECT ..
FROM PriceHistory AS H, Orders AS O
WHERE O.sales_date BETWEEN H.price_start_date
AND COALESCE (price_end_date, CURRENT_DATE);

It is also a good idea to have a VIEW with the current data:

CREATE VIEW CurrentPrices (..)
AS
SELECT ..
FROM PriceHistory
WHERE price_end_date IS NULL;

Now your only problem is to write a stored procedure that will update
the table and insert a new row. You can do this with a single MERGE
statement, or with a short block of SQL/PSM code:

CREATE PROCEDURE UpdateItemPrice
(IN in_upc CHAR(13), IN new_item_price DECIMAL (12,4))
LANGUAGE SQL
BEGIN ATOMIC
UPDATE PriceHistory
SET price_end_date = CURRENT_DATE
WHERE upc = in_upc;
INSERT INTO PriceHistory (upc, price_prev_date, price_start_date,
price_end_date, item_price)
VALUES (in_upc, CURRENT_DATE, CURRENT_DATE + INTERVAL '1' DAY, NULL,
new_item_price);
END;

This will make the price change go into effect tomorrow.

There is a common kludge to repair a failure to design a history table
properly that you can put in a VIEW if you are not able to set things
right. Assume that every day we take a short inventory and put it in
a journal. The journal is a clip board paper form that has one line
per item per day, perhaps with gaps in the data. We want to get this
into the proper format, namely periods shown with a (start_date,
end_date) pair for durations where each item had the same quantity on
hand. This is due to Alejandro Mesa

CREATE TABLE InventoryJournal
(journal_date DATETIME NOT NULL,
item_id CHAR(2) NOT NULL,
PRIMARY KEY (journal_date, item_id),
onhand_qty INTEGER NOT NULL);

WITH ItemGroups
AS
(SELECT journal_date, item_id, onhand_qty,
ROW_NUMBER() OVER(ORDER BY item_id, journal_date, onhand_qty)
- ROW_NUMBER() OVER(PARTITION BY item_id, onhand_qty
ORDER BY journal_date) AS item_grp_nbr
FROM Journal),

QtyByDateRanges
AS
(SELECT MIN(journal_date) AS start_date,
MAX(journal_date) AS end_date,
item_id, onhand_qty
FROM ItemGroups
GROUP BY item_id, onhand_qty, item_grp_nbr)

SELECT start_date, end_date, item_id, onhand_qty
FROM QtyByDateRanges;

This might be easier to see with some data and intermediate steps

INSERT INTO InventoryJournal
VALUES('2013-01-01', 'AA', 100),('2013-01-01', 'BB', 200),
('2013-01-02', 'AA', 100),('2013-01-02', 'BB', 200),
('2013-01-03', 'AA', 100),('2013-01-03', 'BB', 300);

start_date end_date item_id onhand_qty
==========================================
'2013-01-01' '2013-01-03' 'AA' 100
'2013-01-01' '2013-01-02' 'BB' 200
'2013-01-03' '2013-01-03' 'BB' 300

Now, download the Rick Snodgrass book on Temporal Queries in SQL from
the University of Arizona website (it is free).

Reply With Quote
Reply




Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off



Powered by vBulletin Version 3.5.3
Copyright ©2000 - 2012, Jelsoft Enterprises Ltd.