Exclude records based on date and other field - sql-server-2005

I have a situation I have been working on but can't seems to solve it.
I have employee that record their time in the morning and in the afternoon, so as an example, employee 101 recorded two transaction for the entire day as shown below:
EMPNO WORKDATE PAYCODE
101 09/01/14 REG
101 09/01/14 REG
So whenever I see the PAYCODE 'REG' I update the table with another PAYCODE called REG1 in the table for this employee for that day, so the now the table looks like this:
EMPNO WORKDATE PAYCODE
101 09/01/14 REG
101 09/01/14 REG
101 09/01/14 REG1
101 09/01/14 REG1
So now on 09/02/2014 this employee records two more transactions and the table now looks like this
EMPNO WORKDATE PAYCODE
101 09/01/14 REG
101 09/01/14 REG
101 09/01/14 REG1
101 09/01/14 REG1
101 09/02/14 REG
101 09/02/14 REG
Here comes the problem, if I run my query and update the records with PAYCODE REG1 it duplicate the records on 09/01 again:
EMPNO WORKDATE PAYCODE
101 09/01/14 REG
101 09/01/14 REG
101 09/01/14 REG1
101 09/01/14 REG1
101 09/01/14 REG1
101 09/01/14 REG1
101 09/02/14 REG
101 09/02/14 REG
101 09/02/14 REG1
101 09/02/14 REG1
How do I avoid the duplicates, my queries searches for the REG paycode in the last 7 days, if it finds a REG paycode it's suppose to add REG1 to that day but only if there is not already a REG1 there. So if in a day I could have 2 REG paycodes so I add 2 REG1 but if there is only 1 REG then I only add 1 REG1.
I hope this makes sense.
Thank you for your help..

Related

SQL to fetch least 2 salaries from a table department wise

How would be the SQL to fetch least 2 salaries from a table department wise ?
Sample Table:
empid salary Dept
---------------------
101 2000 aaa
102 1000 bbb
103 5000 bbb
104 8000 ccc
105 3000 aaa
106 4000 aaa
107 6000 ccc
108 7000 bbb
109 9000 ccc
Output should be like:
Dept empid salary
----------------------
aaa 101 2000
aaa 105 3000
bbb 102 1000
bbb 103 5000
ccc 104 6000
ccc 107 8000
SELECT
t.dept
,t.empid
,t.salary
FROM
#test t
WHERE
t.empid IN (
SELECT TOP 2
empid
FROM
#test
WHERE
dept = t.dept
ORDER BY
salary
)
ORDER BY
dept,empid
As was pointed out, there may be other people in dept ccc with a salary of 8000 that will be missed.
Following this blog post and supposing the table name is "samptab":
select dept, empid, salary
from samptab
where (
select count(*) from samptab as s
where s.dept = samptab.dept and s.salary <= samptab.salary
) <= 2 order by dept;
You can change the number "2" in the query row if you want more or less rows.

How to join three tables in SQL Server 2012 and calculate ranking based on 2 attributes

I have 3 tables:
tblEmployee
E_ID E_Name E_City
--------------------------------
101 sasa Mumbai
102 sdf California
103 trt Illinois
104 dssd Texas
105 trt Pennsylvania
106 wee Arizona
107 rer Texas
108 wqe California
109 sadd Michigan
tblGen
Tgenerate is boolean value
Emp_ID Tgenerate
--------------------
105 1
108 1
102 1
102 1
102 0
104 1
107 0
108 1
109 0
And the tblStat:
Emp_ID Status
------------------
103 Pending
107 Pending
103 Pending
101 Delivered
104 Pending
104 Pending
108 Pending
101 Delivered
105 Delivered
I have to join these 3 tables and want output like this
E_Name EmployeeID City TgenerateCount Delivered_Count Ranking
TgenerateCount is calculated for every employee. It is count of TgenerateCount having value 1, for ex 102 has 2 TgenerateCount and 109 has 0 TgenerateCount.
Delivered_Count is count of Status of those who has 'Delivered' status. For ex. 101 has 2 Delivered. I want to display every user in the output table.
Any help would be greatly appreciated.
As your two fact tables have a many:1 relationship with your dimension table, you should aggregate them before joining them.
SELECT
e.*,
COALESCE(g.rows, 0) AS TgenerateCount,
COALESCE(s.rows, 0) AS DeliveredCount,
RANK() OVER (ORDER BY COALESCE(g.rows, 0) + COALESCE(s.rows,0) DESC) AS ranking
FROM
tblEmployee e
LEFT JOIN
(
SELECT E_ID, COUNT(*) AS rows FROM tblGen WHERE Tgenerate = 1 GROUP BY E_ID
)
g
ON g.E_ID = e.E_ID
LEFT JOIN
(
SELECT E_ID, COUNT(*) AS rows FROM tblStat WHERE STATUS = 'Delivered' GROUP BY E_ID
)
s
ON s.E_ID = e.E_ID
You've been unclear on how the ranking should be completed, so this simply gives an example ranking.

Oracle issue with reporting SQL

I have a reporting SQL in Oracle which is using the SUM function.
Table Y
CLIENT_NUM LOCATION_CODE EFFECTIVE_DATE EXPIRY_DATE
1234 AB01 1/1/2011 6/30/2014
1234 AB01 7/1/2014 8/31/2014
1234 AB01 9/1/2014 6/30/2015
1234 AB66 1/1/2011 6/30/2014
1234 AB66 7/1/2014 8/31/2014
1234 AB66 9/1/2014 6/30/2015
Table X
CLIENT_NUM LOCATION_CODE EMPLOYEE_COUNT TOTAL_HOURS_WORKED REPORTING_YEAR
1234 AB01 600 12000 2014
1234 AB66 50 11000 2014
SQL:
SELECT SUM(x.EMPLOYEE_COUNT)
OVER (PARTITION BY CASE ':input_parm:'
WHEN 'LOCATION' THEN y.LOCATION_CODE || ' ' || y.LOCATION_NAME
WHEN 'CLIENT' THEN y.CLIENT_NUM|| ' ' ||z.CLIENT_NAME
END
) AS EMPLOYEE_COUNT
, SUM(x.TOTAL_HOURS_WORKED)
OVER (PARTITION BY CASE ':input_parm:'
WHEN 'LOCATION' THEN y.LOCATION_CODE || ' ' || y.LOCATION_NAME
WHEN 'CLIENT' THEN y.CLIENT_NUM|| ' ' ||z.CLIENT_NAME
END
) AS TOTAL_HOURS_WORKED
FROM Y
LEFT OUTER JOIN X
ON Y.CLIENT_NUM = X.CLIENT_NUM
AND Y.LOCATION_CODE = X.LOCATION_CODE
AND X.REPORTING_YEAR = '2014'
AND location.EFFECTIVE_DATE BETWEEN TO_DATE('01-JAN-:in_reporting_year:','DD-MON-YYYY')
AND TO_DATE('31-DEC-:in_reporting_year:','DD-MON-YYYY')
WHERE Y.CLIENT_NUM='1234'
AND (Y.LOCATION_CODE='AB66' OR Y.LOCATION_CODE='AB01')
This is doubling the numbers up and returning the following when passing "CLIENT" or "LOCATION" for :input_parm: and 2014 for :in_reporting_year:
EMPLOYEE_COUNT TOTAL_HOURS_WORKED
1300 46000
1300 46000
This is the expected output:
EMPLOYEE_COUNT TOTAL_HOURS_WORKED
650 23000
650 23000
How can I further filter the join to match only one?
You have two rows in Y for the same location_code and client_num pairs that you're joining on. So the join is duplicating your results and thus the doubling in the totals.
I'm guessing you'll need to match on one of the dates values somehow.
EDIT: To address your question in comments you could try changing FROM Y to the following:
FROM (SELECT DISTINCT CLIENT_NUM, LOCATION_CODE FROM Y) as Y

Parent Child relation in SQL Server

I have a table with this structure:
ParentProjectID ChildProjectID
------------------------------
101 102
102 103
103 104
201 202
202 203
Let me explain the scenario, when we renew a project we treat this as a new project and enter it under its parent project.
Like 102 is child project of its parent 102 and child 103's parent is 102 and so on.
Now, my question is to find out the grand parent, parent and child.
Like in above case 101 is grand parent of 102,103 and 104. And 102 is parent of 103 and 104.
So, I want my result as:
(If I pass 101 as parameter of ParentProjectID)
ParentProjectID ChildProjectID
101 102
101 103
101 104
Any help will be appreciated.
You can use recursive common table expression:
create procedure usp_Descendants
(
#ParentProjectID int
)
as
begin
;with cte as (
select
T.ChildProjectID
from Table1 as T
where T.ParentProjectID = #ParentProjectID
union all
select
T.ChildProjectID
from cte as c
inner join Table1 as T on T.ParentProjectID = c.ChildProjectID
)
select
#ParentProjectID, c.ChildProjectID
from cte as c
end
exec usp_Descendants #ParentProjectID = 101;
-----------
101 102
101 103
101 104
exec usp_Descendants #ParentProjectID = 101;
-----------
102 103
102 104
sql fiddle demo

Access Query; Creating Master/Slave from list

Asked a question a few days ago, but have decided to go down a differnt route so am re-doing the question as the edit's were getting a bit messy.
I have a list of data containing two columns:
pID sKey
100 8611
100 2318
101 3516
101 5413
102 6546
102 5646
102 8411
103 8795
103 5845
The first sKey to appear would become the Master sKey for that pID and each sKey after would be a slave. The data would look like this.
pID sKey sKey_1
100 8611 2318
101 3516 5413
102 6546 5646
102 6546 8411
103 8795 5845
This query gets me close
SELECT MyTable.pID, MyTable.sKey, MyTable_1.sKey
FROM MyTable
INNER JOIN MyTable AS MyTable_1
ON MyTable.pID = MyTable_1.pID
WHERE (((IIf([MyTable.sKey]=[MyTable_1.sKey],"Y","N"))="N"))
pID sKey sKey
100 2318 8611
100 8611 2318
101 3516 5413
101 5413 3516
102 5646 6546
102 5646 8411
102 6546 5646
102 6546 8411
102 8411 5646
102 8411 6546
103 5845 8795
103 8795 5845
But as you can see it reverses the order and doubles each one up, and when it hits an instance where there is 3 or more sKey's it goes a bit crazy :\
Anyone have any ideas, or can point me in the right direction?
If you're trying to use the MIN(skey) as your Master, then something like this should work:
select
p.pId,
p.skey,
p3.skey skey1
from mytable p
join (select pID, min(skey) minskey
from mytable
group by pID
) p2 on p.pid = p2.pid and p.skey = p2.minskey
join mytable p3 on p.pid = p3.pid and p.skey != p3.skey
SQL Fiddle Demo
This produces slightly different results than yours above.
If your desired results are to use the first skey that shows up, then I'd recommend adding an Identity/AutoNumber column to your table just to seed from. You can't guarantee the order of the results without that column. So assuming you were to add such a column, then something like this should work:
select
p.pId,
p.skey,
p3.skey skey1
from mytable p
join (select pID, min(id) minId
from mytable
group by pID
) p2 on p.id = p2.minId
join mytable p3 on p.pid = p3.pid and p.id <> p3.id
order by p.pid, p3.id
SQL Fiddle Demo With AutoNumber