copy rows from one tabel into another without duplicating in second table - sql-server-2005

l have two tables, Table1 columns as follows:
id surname level term pyear status
a1 peterson form1 first_term 2014 active
a2 chanaka form1 first_term 2014 active
Table2 columns pretty much similar to Table1 as follows:
id surname level term pyear
Table1 Primary Key:id
Table2 Primary Key:(id,level, term, pyear)
Here is the scenario, Table1 records can only be inserted once and once inserted, a record can then be updated such that level, term and pyear can change, e.g level and pyear change at the same time because l can only upgrade records from say form1 to form2 at once when moving from 2014 to 2015. As for, term, the same level and year can have first_term, second_term and third_term. l have to run the above query every time l move from one term to another, say first_term to second_term or from one year to the next, say from 2014 to 2015 which will then change levels say from form1 to form2. When the query is run, the updated records in Table1 have to be reflected as newly inserted records in Table2. For an instance, lets say Table1 contents have gone through the following updates:
Table1
id surname level term pyear status
a1 peterson form1 first_term 2014 active
a2 chanaka form1 first_term 2014 active
Table1
id surname level term pyear status
a1 peterson form1 second_term 2014 active
a2 chanaka form1 second_term 2014 active
Table1
id surname level term pyear status
a1 peterson form1 third_term 2014 active
a2 chanaka form1 third_term 2014 active
Table1
id surname level term pyear status
a1 peterson form2 first_term 2015 active
a2 chanaka form2 first_term 2015 active
For the above transitions in Table1, Table2 has to be appear as follows:
Table2
id surname level term pyear
a1 peterson form1 first_term 2014
a2 chanaka form1 first_term 2014
a1 peterson form1 second_term 2014
a2 chanaka form1 second_term 2014
a1 peterson form1 third_term 2014
a2 chanaka form1 third_term 2014
a1 peterson form2 first_term 2015
a2 chanaka form2 first_term 2015
My problem is, the query can only insert into Table2 as long as there is no any other record that has in Table2 with the same level, term and year. If there is at least one record that has the same level, term and year, no matter there are other records recently entered in Table1, they will not be inserted. If l try to remove the 'if not exists' statement, it will also insert the records in Table2 as long as there is no any record with the same level, term and year in Table2 otherwise it reports that it cannot insert based on primary key and then it terminates. How can l go around the problem without duplicating records in Table2.
Th query l ran is as follows:
create proc sp_extract(
#level nvarchar(50),
#term nvarchar(50),
#pyear int
)
as
if not exists(select id,
surname,
level,
term,
pyear
from Table2 where level=#level and term=#term and pyear=#pyear)
insert into Table2
(
id,
surname,
level,
term,
pyear
)
select id,
surname,
level,
term,
pyear
from Table1 where level=#level and term=#term and pyear=#pyear

Related

How do I join six tables in SQL while only including certain rows?

I have 6 tables of people corresponding to 6 calendar years of data,2010-2015. Each row in each table has a unique variable id corresponding to an individual who participated for the entire year, and each table has the variable year which is set to whichever participation year it is.
If an individual doesn't participate for the entire year, there is no corresponding row in that table.
For example,
enyear2010
id year (other variables)
0000001 2010 .
0000002 2010 .
000003 2010 .
0000004 2010 .
enyear2011
id year (other variables)
0000002 2011 .
0000003 2011 .
0000004 2011 .
0000005 2011 .
enyear2012
id year (other variables)
0000001 2012 .
0000002 2012 .
0000003 2012 .
0000005 2012 .
In the case of id 1, they didn't participate for the entirety of 2011 but did come back in in 2012, id 4 left in 2012, and id 5 joined in 2011.
I’d like to join all these tables together and take rows which occur in at least 2 consecutive years (such that for id 1, they wouldn’t be in this joined table), and create a new variable that corresponds to the # of years a person is in the dataset and when that person started.
merged-table
id startyear enrolledyears (other variables)
0000002 2010 3 .
0000003 2010 3 .
0000004 2010 2 .
0000005 2011 2 .
So far, I was able to conceptualize this as a series of left joins, such that the year variable in each table becomes the startyear variable, but I think the process breaks down when somebody enters not in 2010.
Any advice is greatly appreciated!
Firstly, splitting things into yearly-named table is not a good table design. You should just put everything in the same table. Now every year that you add will need to be added to whatever SQL you come up with.
You can make it look like one table like this:
SELECT ID, Year FROM entear2010
UNION ALL
SELECT ID, Year FROM entear2011
UNION ALL
SELECT ID, Year FROM entear2012
Now you can use that construct to get what you want. You put that into something called a CTE:
WITH AllData AS (
SELECT ID, Year FROM entear2010
UNION ALL
SELECT ID, Year FROM entear2011
UNION ALL
SELECT ID, Year FROM entear2012
)
SELECT * FROM AllData
Now you can 'self join' to check if an id is in the prior year also:
WITH AllData AS (
SELECT ID, Year FROM entear2010
UNION ALL
SELECT ID, Year FROM entear2011
UNION ALL
SELECT ID, Year FROM entear2012
)
SELECT Current.ID, Current.Year
FROM AllData As Current
INNER JOIN AllData As Prior
ON Current.ID = Prior.ID
AND Current.Year-1 = Prior.Year
That gets you the list of people with two consecutive years. Now you just summarise it:
WITH AllData AS (
SELECT ID, Year FROM entear2010
UNION ALL
SELECT ID, Year FROM entear2011
UNION ALL
SELECT ID, Year FROM entear2012
)
SELECT ID, COUNT(*) YearsEnrolled, MIN(Year) As StartYear
FROM AllData
WHERE ID IN (
SELECT DISTINCT Current.ID
FROM AllData As Current
INNER JOIN AllData As Prior
ON Current.ID = Prior.ID
AND Current.Year-1 = Prior.Year
)
GROUP BY ID
I think that's what you're after.
There is probably a smarter way to do it using windowing functions... but someone else will no doubt post it.
You have to merge all tables first (By union all or creating temp table), then run below SQL:
select * from (
select MEMBER_ID, max(YEAR_NUM) MAX_YEAR, MIN(YEAR_NUM) MIN_YEAR, COUNT(YEAR_NUM) YEAR_COUNT
from merged_tables
group by MEMBER_ID) w1
where MAX_YEAR=MIN_YEAR+YEAR_COUNT-1 and YEAR_COUNT>1
Above SQL will return all member ID whose consecutive enrolled years is greater than one year.

Need to display distinct value

Note:Table is not inserting correctly. Kindly understand
(Col1-ID,Col2-Name,Col3-Type(a1,b1,c1,d1),Col4-Year)
Table: Example1
This is my query,
select distinct name,type from example1
Id Name Type Year
1 sai a1 2017
2 sai b1 2016
3 sai c1 2015
4 joe a1 2016
5 Michael c1 2015
6 Michael d1 2013
7 Michael a1 2012
and my query is, when I am selecting name and type from example1 table the result is shown below
Id Name Type
1 sai a1
2 sai b1
3 joe a1
4 Michael c1
5 Michael d1
I need a latest year value but it displaying duplicate value(with latest year value and previous year value)
Please help on this.
You can take the year for Year part of current date and use query with a WHERE clause for current year.
DECLARE #currYear INT = DATEPART(yyyy, GETDATE())
select distinct name,type from example1 WHERE Year = #currYear
Your query is returning what you asked for, you selected the distinct name and type so that's what you will get, the distinct values for both those columns.
If you just want the distinct name then you can do:
SELECT DISTINCT
name
FROM example1;
If you want the type too then you need to decide what aggregation you are going to do on it e.g. the max, min, count etc... Then you can use GROUP BY.
If you want the distinct name and the most recnet type then you can use:
SELECT
name,
MAX(type)
FROM example1
GROUP BY name
Also type and name are keywords in SQL, best practise is to not use those for column names
You can use GROUP BY Statement
Select name,type from example1 where year=YEAR(CURDATE()) group by name,type;

Oracle SQL - finding sets that contain another set

Say I have a table A that contains a list of a potential employees ID's and their professional skills in the form of a skill code:
ID | skill code
005 12
005 3
007 42
007 8
013 6
013 22
013 18
And I have another table B that lists several job position ID's and their corresponding required skill ID's:
Job ID | skill code
1 3
1 32
1 21
1 44
2 15
2 62
.
.
.
How can I find out which Job Id's a specific person is qualified for? I need to select all Job Id's that contain all the person's skills. Say for instance I need to find all job ID's that employee ID 003 is qualified for, how would I structure an Oracle SQL query to get this information?
I want to be able to enter any employee ID in a WHERE clause to find what jobs that person is qualified for.
An idea would be to count the number of skills for every person and job:
SELECT A.id as person_id,
B.JOB_ID
FROM A
JOIN B
ON A.skill_code=B.skill_code
GROUP BY a.id, b.job_id
HAVING count(*) = (select count(*) from b b2 where b2.job_id = b.job_id);
Not tested and assuming that tables are well normalized.
UPDATE after the OP's comment.
It is asked for all the jobs which necessitate all skills of a person:
SELECT A.id as person_id,
B.JOB_ID
FROM A
JOIN B
ON A.skill_code=B.skill_code
GROUP BY a.id, b.job_id
HAVING count(*) = (select count(*) from a a2 where a2.job_id = b.job_id);
Update2: The question was updated with:
I want to be able to enter any employee ID in a WHERE clause to find what jobs that person is qualified for.
For this, you just add WHERE a.id = :emp_id to the first query. (above group by)
Try this one
WITH b1 AS
(SELECT job_id,
skill,
COUNT(*) over (partition BY job_id order by job_id) rr
FROM b
) ,
res1 AS
(SELECT a.id,
b1.job_id,
rr,
COUNT(*) over (partition BY id, job_id order by id) rr2
FROM A
JOIN B1
ON A.skill=B1.skill
)
SELECT id, job_id FROM res1 WHERE rr=rr2

Sum values in one column and add to another table

My Table(BOB) is look like this:
Year Month Value
2010 1 100
2010 2 100
2010 3 100
2010 4 100
2010 5 100
I would like to add YTD values to another table (BOB2)
more exactly I want to see BOB 2 table like
Year Month Value
2010 1 100
2010 2 200
2010 3 300
2010 4 400
2010 5 500
See the answer below. I have simplified the query.
select
concat(cast(t1.year as char), cast(t1.month as char)) period_current,
sum(t1.amount) amount
from bob t1
left join bob t2 on
(t2.year + t2.month) <= (t1.year + t1.month)
group by
(t1.year + t1.month);
What the query is doing is using t1 as the base table and joining on the period (year + month) then you want to sum the amounts prior to that including the current amount. I haven't added in all the edge cases, but this gives you something to start from. If you are restricting your query to a single year, this should be enough.
Well, I think I understand what you are trying to do.. but if not, please re-phrase your question... You can accomplish what you have asked by using the following SQL.
--INSERT INTO BOB2 (Year, ID, Value)
SELECT a.Year, a.ID, (SELECT SUM(b.Value)
FROM BOB b
WHERE b.ID <= a.ID) as RunningTotalValue
FROM BOB a
ORDER BY a.Value;
Here is a SQLFiddle for you to look at.
EDIT: Change the ID column to "Month" after seeing the edit to your post.

Query malfunction in SQLServerCE using with VB.NET

I am working on a project, where my target is to automate the fee-system of a school.
I am implementing the project in VB.NET 2012 and using SQLServerCE for handling data.
My situation is like this :
I have two tables namely : 'feecollection' and 'StudentDetails'
The columns of the table feecollection are as follows
Similarly, the columns of the table StudentDetails are as follows
Now I want to find out the names of student(s) who are defaulters.
I am doing the filtering on the basis of Name, Months and the defaulter fields.
Logic : The name of the students who are in fee collection for a given month have paid, so defaults are all names which are in StudentDetails but not in feecollection whose defaulter field is '1' (1 indicates that they have paid).
My query :
select StudentDetails.Name where StudentDetails.Name not in
(Select feecollection.Name, feecollection.Month, feecollection.defaulter,
StudentDetails.Name from feecollection
inner join StudentDetails on feecollection.Name = StudentDetails.Name
where StudentDetails.Name = 'def' and feecollection.month = 'January'
and feecollection.defaulter = '1'
But this query is not working properly.
Where did I go wrong on this ?
Assuming that the defaulter field is '0' or the feecollection record is missing when the student has NOT payed, I would use a SQL statement something like this.
SELECT StudentDetails.Name FROM StudentDetails
LEFT JOIN feecollection ON StudentDetails.Name = feecollection.Name
AND feecollection.Payment_For_Month = 'Jan'
WHERE feecollection.defaulter = '0' OR feecollection.defaulter IS NULL;
This way you should get all records in StudentDetails where the matching feecollection record either has '0' in defaulter, or is not present.
EDIT
If you still want to use the IN operator this statement should do it:
SELECT StudentDetails.Name FROM StudentDetails WHERE
StudentDetails.Name NOT IN
(SELECT feecollection.Name FROM feecollection
WHERE feecollection.Payment_For_Month = 'Feb'
AND feecollection.defaulter = '1')
I've tested this out on a simplified dataset:
StudentDetails:
Name Class Section
------------------------
Adam 101 Sect1
Bob 101 Sect
Charlie 101 Sect2
feecollection:
Name Payment_For_Month defaulter
--------------------------------------
Adam Jan 1
Adam Feb 1
Bob Jan 1
With this data the top statement returns only Charlie, while the second statement returns Bob and Charlie.