Home All Groups Group Topic Archive Search About

Need advice with a query

Author
29 Sep 2005 3:09 PM
News
Hi,

I need an advice.

I have a new project where I have to store employee salary values in order
to keep historical representation of all changes done to the employee
record. Below is the approximate model how I am going to proceed.
My question is, how would I pull ee salary at certain date, say "what was
employee salary on July 1st, 2005".

I know I can do something like that:

SELECT TOP 1 salary FROM tEmployeeSalary
WHERE employee_id = 1
AND DateDiff(dd, 'July 1, 2005', effective_date) >= 0
ORDER BY effective_date ASC

But I would need to use it in joins with other tables. So, is it possible to
write a query to get to the required record without ORDERing and using TOP?



begin tran
create table tEmployeeSalary
(
employee_id int,
salary money,
effective_date datetime,
is_active bit
)
insert into tEmployeeSalary (employee_id, salary, effective_date, is_active)
values (1, 45000, 'dec 12, 2004', 1)

insert into tEmployeeSalary (employee_id, salary, effective_date, is_active)
values (1, 49000, 'mar 1, 2005', 1)

insert into tEmployeeSalary (employee_id, salary, effective_date, is_active)
values (1, 54000, 'june 20, 2005', 1)

insert into tEmployeeSalary (employee_id, salary, effective_date, is_active)
values (1, 67000, 'sep 10, 2005', 1)

select * from tEmployeeSalary

drop table tEmployeeSalary
commit tran


Thank you in advance for all suggestions.

Gena

Author
29 Sep 2005 3:23 PM
Jerry Spivey
News,

Assuming salarys are continually increasing and never decrease...maybe this
would work:

SELECT  MAX(SALARY)
FROM TEMPLOYEESALARY
WHERE   EMPLOYEE_ID = 1 AND EFFECTIVE_DATE <= '7/1/2005'

HTH

Jerry
Show quote
"News" <zoom191***@yahoo.com> wrote in message
news:S8Cdna9sLsQCnqHeRVn-iA@magma.ca...
> Hi,
>
> I need an advice.
>
> I have a new project where I have to store employee salary values in order
> to keep historical representation of all changes done to the employee
> record. Below is the approximate model how I am going to proceed.
> My question is, how would I pull ee salary at certain date, say "what was
> employee salary on July 1st, 2005".
>
> I know I can do something like that:
>
> SELECT TOP 1 salary FROM tEmployeeSalary
> WHERE employee_id = 1
> AND DateDiff(dd, 'July 1, 2005', effective_date) >= 0
> ORDER BY effective_date ASC
>
> But I would need to use it in joins with other tables. So, is it possible
> to write a query to get to the required record without ORDERing and using
> TOP?
>
>
>
> begin tran
> create table tEmployeeSalary
> (
> employee_id int,
> salary money,
> effective_date datetime,
> is_active bit
> )
> insert into tEmployeeSalary (employee_id, salary, effective_date,
> is_active)
> values (1, 45000, 'dec 12, 2004', 1)
>
> insert into tEmployeeSalary (employee_id, salary, effective_date,
> is_active)
> values (1, 49000, 'mar 1, 2005', 1)
>
> insert into tEmployeeSalary (employee_id, salary, effective_date,
> is_active)
> values (1, 54000, 'june 20, 2005', 1)
>
> insert into tEmployeeSalary (employee_id, salary, effective_date,
> is_active)
> values (1, 67000, 'sep 10, 2005', 1)
>
> select * from tEmployeeSalary
>
> drop table tEmployeeSalary
> commit tran
>
>
> Thank you in advance for all suggestions.
>
> Gena
>
Author
29 Sep 2005 3:40 PM
David Portas
You don't really have every column nullable do you? What are the keys?
Thanks for the DDL and sample data but it would be more helpful if it
was accurate and complete. Assuming that (employee_id, effective_date)
is unique, try this:

SELECT employee_id, salary
FROM tEmployeeSalary AS E
WHERE effective_date =
  (SELECT MAX(effective_date)
   FROM tEmployeeSalary
   WHERE employee_id = E.employee_id
    AND effective_date <= '20050701') ;

Be careful with the MONEY datatype. Precision is lost when you multiply
and divide MONEY. In my opinion MONEY is unsuitable for financial data.
(yes, seriously!)

--
David Portas
SQL Server MVP
--
Author
29 Sep 2005 4:26 PM
News
Thanks David,

The data in my table does not allow nulls, although employee_id id is not
unique and the effective_date can repeat in cases when mistake was made and
I can allow to change salary on the same date or earlier (in this case
is_active will be set to 0).

And, thanks for "money" advice, good point.
I guess, I cannot get away from "TOP - ORDER" or subquery. I think I will
write a UDF and call it anytime I need a salary at a time point.

Another question, would it be a good idea to add a field - primary key
identity? emp_salary_id...

Thanks,

Gena

Show quote
"David Portas" <REMOVE_BEFORE_REPLYING_dpor***@acm.org> wrote in message
news:1128008402.193130.131230@g14g2000cwa.googlegroups.com...
> You don't really have every column nullable do you? What are the keys?
> Thanks for the DDL and sample data but it would be more helpful if it
> was accurate and complete. Assuming that (employee_id, effective_date)
> is unique, try this:
>
> SELECT employee_id, salary
> FROM tEmployeeSalary AS E
> WHERE effective_date =
>  (SELECT MAX(effective_date)
>   FROM tEmployeeSalary
>   WHERE employee_id = E.employee_id
>    AND effective_date <= '20050701') ;
>
> Be careful with the MONEY datatype. Precision is lost when you multiply
> and divide MONEY. In my opinion MONEY is unsuitable for financial data.
> (yes, seriously!)
>
> --
> David Portas
> SQL Server MVP
> --
>
Author
29 Sep 2005 4:49 PM
David Portas
> Another question, would it be a good idea to add a field - primary key
> identity? emp_salary_id...

More important to add a constraint on the relevant business key. Here
I'm guessing:

ALTER TABLE tEmployeeSalary
ADD CONSTRAINT ak1_employee_salary
UNIQUE (employee_id, effective_date)

or:

ALTER TABLE tEmployeeSalary
ADD CONSTRAINT pk_employee_salary
PRIMARY KEY (employee_id, effective_date)

You can add the IDENTITY key if you need to reference it in another
table but otherwise it would be redundant. Every table should of course
have at least one candidate key.

--
David Portas
SQL Server MVP
--
Author
29 Sep 2005 5:34 PM
News
Hmm,

I cannot make PRIMARY KEY (employee_id, effective_date) because it will not
allow me to set different salaries for the same employee on the same date.
What if administrator made a mistake and noticed it few months later. I
cannot update it, I will need to add a new record with the same employee_id
and the same effective_date.

Thanks



Show quote
"David Portas" <REMOVE_BEFORE_REPLYING_dpor***@acm.org> wrote in message
news:1128012586.541851.238920@z14g2000cwz.googlegroups.com...
>> Another question, would it be a good idea to add a field - primary key
>> identity? emp_salary_id...
>
> More important to add a constraint on the relevant business key. Here
> I'm guessing:
>
> ALTER TABLE tEmployeeSalary
> ADD CONSTRAINT ak1_employee_salary
> UNIQUE (employee_id, effective_date)
>
> or:
>
> ALTER TABLE tEmployeeSalary
> ADD CONSTRAINT pk_employee_salary
> PRIMARY KEY (employee_id, effective_date)
>
> You can add the IDENTITY key if you need to reference it in another
> table but otherwise it would be redundant. Every table should of course
> have at least one candidate key.
>
> --
> David Portas
> SQL Server MVP
> --
>
Author
29 Sep 2005 5:42 PM
Alexander Kuznetsov
another option would be to have effective_from and effective_to columns
in the table
Author
29 Sep 2005 7:16 PM
News
I am trying to stay away from this, because I would need to maintain
effective_to and update it along with addition of a new record.

Spasibo, Sasha

Gena




Show quote
"Alexander Kuznetsov" <AK_TIREDOFSPAM@hotmail.COM> wrote in message
news:1128015747.429032.246440@g43g2000cwa.googlegroups.com...
> another option would be to have effective_from and effective_to columns
> in the table
>
Author
29 Sep 2005 7:43 PM
Alexander Kuznetsov
Gena,

one more approach:

SELECT  employee_id, salary
  FROM tEmployeeSalary ES1
WHERE ES1.employee_id = 1
AND ES2.effective_date <= '07/01/2004'
and not exists(SELECT 1
     FROM tEmployeeSalary ES2
     WHERE ES2.employee_id  = ES1.employee_id
     AND ES1.effective_date < ES2.effective_date
     AND ES2.effective_date <= '07/01/2004')

not sure which one would perform better

Udachi!
Author
29 Sep 2005 8:15 PM
News
Now, I've got 3 statements to choose from:

1.
SELECT
TOP 1 salary, effective_date
FROM EmployeeSalary
WHERE employee_id = 1
AND DateDiff(dd, effective_date, 'aug 1, 2005') >=0
ORDER BY effective_date DESC

2.
SELECT salary, effective_date
FROM EmployeeSalary AS E
WHERE employee_id = 1
AND effective_date =
(SELECT MAX(effective_date)
FROM EmployeeSalary
WHERE employee_id = E.employee_id
AND DateDiff(dd, effective_date, 'aug 1, 2005') >= 0)

3.
SELECT  salary, effective_date
FROM EmployeeSalary ES1
WHERE ES1.employee_id = 1
AND ES1.effective_date <= 'aug 1, 2005'
AND NOT exists(SELECT 1
FROM EmployeeSalary ES2
WHERE ES2.employee_id  = ES1.employee_id
AND ES1.effective_date < ES2.effective_date
AND ES2.effective_date <= 'aug 1, 2005')

I checked Statistics in Query Analyzer and it seems overall statement #2
looks the best. Although, in some categories it looses. What is the most
important to look at when checking stats and trace? I imagine Reads are very
important in Trace. But, there are also

Application Profile Statistics
  Number of SELECT statements
  Rows effected by SELECT statements
  Number of user transactions

Network Statistics
  Number of server roundtrips
  Number of TDS packets sent
  Number of TDS packets received
  Number of bytes sent
  Number of bytes received

Time Statistics
  Cumulative client processing time
  Cumulative wait time on server replies



Thanks,

Gena




Show quote
"Alexander Kuznetsov" <AK_TIREDOFSPAM@hotmail.COM> wrote in message
news:1128022980.883781.112920@o13g2000cwo.googlegroups.com...
> Gena,
>
> one more approach:
>
> SELECT  employee_id, salary
>  FROM tEmployeeSalary ES1
> WHERE ES1.employee_id = 1
> AND ES2.effective_date <= '07/01/2004'
> and not exists(SELECT 1
>     FROM tEmployeeSalary ES2
>     WHERE ES2.employee_id  = ES1.employee_id
>     AND ES1.effective_date < ES2.effective_date
>     AND ES2.effective_date <= '07/01/2004')
>
> not sure which one would perform better
>
> Udachi!
>
Author
29 Sep 2005 5:52 PM
David Portas
So add a "created_date" or "modified_date" to the key. It seems your
original specification was too much of a simplified example. Adding
duplicate effective dates without further information and just updating
"is_active" would mean you would lose the audit trail containing the
sequence of changes.

--
David Portas
SQL Server MVP
--
Author
29 Sep 2005 7:09 PM
News
Thanks a lot,

I added created date and made it part of PK (employee_id, effective_date,
trx_date).



Show quote
"David Portas" <REMOVE_BEFORE_REPLYING_dpor***@acm.org> wrote in message
news:1128016367.702743.260980@g47g2000cwa.googlegroups.com...
> So add a "created_date" or "modified_date" to the key. It seems your
> original specification was too much of a simplified example. Adding
> duplicate effective dates without further information and just updating
> "is_active" would mean you would lose the audit trail containing the
> sequence of changes.
>
> --
> David Portas
> SQL Server MVP
> --
>
Author
29 Sep 2005 5:58 PM
Payson
If you can't define a primary key, then you are sunk.  SQL has no
order.  If you have 2 entries for the same employee with the same
effective date, which do you wish to select?  The higher salary?  The
lower?  The one entered last? (sorry, that information is not
available).  select top ...  has no meaning without an order by -
duplicates can appear in any order SQL Server wants to show them.

Given the requirements I have seen so far, you can't get there from
here.

You have gotten quite a bit of good, professional advice from the
posters in this thread.  You may want to rethink things a bit.

Good luck.

Payson

News wrote:
Show quote
> Hmm,
>
> I cannot make PRIMARY KEY (employee_id, effective_date) because it will not
> allow me to set different salaries for the same employee on the same date.
> What if administrator made a mistake and noticed it few months later. I
> cannot update it, I will need to add a new record with the same employee_id
> and the same effective_date.
>
> Thanks
>
>
>
> "David Portas" <REMOVE_BEFORE_REPLYING_dpor***@acm.org> wrote in message
> news:1128012586.541851.238920@z14g2000cwz.googlegroups.com...
> >> Another question, would it be a good idea to add a field - primary key
> >> identity? emp_salary_id...
> >
> > More important to add a constraint on the relevant business key. Here
> > I'm guessing:
> >
> > ALTER TABLE tEmployeeSalary
> > ADD CONSTRAINT ak1_employee_salary
> > UNIQUE (employee_id, effective_date)
> >
> > or:
> >
> > ALTER TABLE tEmployeeSalary
> > ADD CONSTRAINT pk_employee_salary
> > PRIMARY KEY (employee_id, effective_date)
> >
> > You can add the IDENTITY key if you need to reference it in another
> > table but otherwise it would be redundant. Every table should of course
> > have at least one candidate key.
> >
> > --
> > David Portas
> > SQL Server MVP
> > --
> >
Author
29 Sep 2005 7:14 PM
News
Yes, you are right,

I am still in the process of deciding. I added date of transaction as a
datetime to the table and this will be sort factor when employee_id and
effective_date are the same. Although, effective_date is also datetime data
type, so it carries timestamp.


Show quote
"Payson" <payso***@hotmail.com> wrote in message
news:1128016717.161132.122570@g49g2000cwa.googlegroups.com...
> If you can't define a primary key, then you are sunk.  SQL has no
> order.  If you have 2 entries for the same employee with the same
> effective date, which do you wish to select?  The higher salary?  The
> lower?  The one entered last? (sorry, that information is not
> available).  select top ...  has no meaning without an order by -
> duplicates can appear in any order SQL Server wants to show them.
>
> Given the requirements I have seen so far, you can't get there from
> here.
>
> You have gotten quite a bit of good, professional advice from the
> posters in this thread.  You may want to rethink things a bit.
>
> Good luck.
>
> Payson
>
> News wrote:
>> Hmm,
>>
>> I cannot make PRIMARY KEY (employee_id, effective_date) because it will
>> not
>> allow me to set different salaries for the same employee on the same
>> date.
>> What if administrator made a mistake and noticed it few months later. I
>> cannot update it, I will need to add a new record with the same
>> employee_id
>> and the same effective_date.
>>
>> Thanks
>>
>>
>>
>> "David Portas" <REMOVE_BEFORE_REPLYING_dpor***@acm.org> wrote in message
>> news:1128012586.541851.238920@z14g2000cwz.googlegroups.com...
>> >> Another question, would it be a good idea to add a field - primary key
>> >> identity? emp_salary_id...
>> >
>> > More important to add a constraint on the relevant business key. Here
>> > I'm guessing:
>> >
>> > ALTER TABLE tEmployeeSalary
>> > ADD CONSTRAINT ak1_employee_salary
>> > UNIQUE (employee_id, effective_date)
>> >
>> > or:
>> >
>> > ALTER TABLE tEmployeeSalary
>> > ADD CONSTRAINT pk_employee_salary
>> > PRIMARY KEY (employee_id, effective_date)
>> >
>> > You can add the IDENTITY key if you need to reference it in another
>> > table but otherwise it would be redundant. Every table should of course
>> > have at least one candidate key.
>> >
>> > --
>> > David Portas
>> > SQL Server MVP
>> > --
>> >
>
Author
29 Sep 2005 3:55 PM
Perayu
You can try to use subquery:

SELECT  employee_id, salary
  FROM tEmployeeSalary ES1
WHERE ES1.employee_id = 1
  AND ES1.effective_date = (SELECT Max(ES2.effective_date )
                                              FROM tEmployeeSalary ES2
                                              WHERE ES2.employee_id  =
ES1.employee_id
                                                 AND ES2.effective_date <=
'07/01/2004')

Perayu

Show quote
"News" <zoom191***@yahoo.com> wrote in message
news:S8Cdna9sLsQCnqHeRVn-iA@magma.ca...
> Hi,
>
> I need an advice.
>
> I have a new project where I have to store employee salary values in order
> to keep historical representation of all changes done to the employee
> record. Below is the approximate model how I am going to proceed.
> My question is, how would I pull ee salary at certain date, say "what was
> employee salary on July 1st, 2005".
>
> I know I can do something like that:
>
> SELECT TOP 1 salary FROM tEmployeeSalary
> WHERE employee_id = 1
> AND DateDiff(dd, 'July 1, 2005', effective_date) >= 0
> ORDER BY effective_date ASC
>
> But I would need to use it in joins with other tables. So, is it possible
> to write a query to get to the required record without ORDERing and using
> TOP?
>
>
>
> begin tran
> create table tEmployeeSalary
> (
> employee_id int,
> salary money,
> effective_date datetime,
> is_active bit
> )
> insert into tEmployeeSalary (employee_id, salary, effective_date,
> is_active)
> values (1, 45000, 'dec 12, 2004', 1)
>
> insert into tEmployeeSalary (employee_id, salary, effective_date,
> is_active)
> values (1, 49000, 'mar 1, 2005', 1)
>
> insert into tEmployeeSalary (employee_id, salary, effective_date,
> is_active)
> values (1, 54000, 'june 20, 2005', 1)
>
> insert into tEmployeeSalary (employee_id, salary, effective_date,
> is_active)
> values (1, 67000, 'sep 10, 2005', 1)
>
> select * from tEmployeeSalary
>
> drop table tEmployeeSalary
> commit tran
>
>
> Thank you in advance for all suggestions.
>
> Gena
>

AddThis Social Bookmark Button