Normalize data with index from table - sql

I have a table (call it tblContractor) like so: (first row in intentionally empty):
ContractorId ContractorName LicenseNumber
0
1 Smith Inc A12345
43 Joe's LLC B4C5t6
4 SureFix Co. 77987
77 ReadyMix 009ABCV
and a table tblProject like so:
ProjectId Name ContractorName ContractorId
32 SureFix Co. NULL
40 Joe's LLC NULL
42 ReadyMix NULL
44 Smith Inc NULL
I've just created that last column, ContractorId, because I want to normalize the data,
i.e. have the ContractorName in only tblContractor and an index to the Contractor in tblProject.
So tblProject will look like:
ProjectId Name ContractorName ContractorId
32 SureFix Co 77987
40 Joe's LLC B4C5t6
42 ReadyMix 009ABCV
44 Smith Inc A12345
How do I do this?
This is what I've go so far but it doesn't work:
SELECT project.ProjectId, project.Name, project.ContractorName, project.ContractorId
FROM tblProject project
WHERE NOT EXISTS (
SELECT TOP 1 *
FROM tblContractor contractor
WHERE project.ContractorName = contractor.ContractorName)
Order by ContractorName
Sorry for the table formatting. I looked at the questions about table formatting for SO questions and I guess there really isn't a good way to do it.

Try starting with this to get the contractorid data moved over:
update a set a.contractorid=b.contractorid from tblProject a
join tblContractor b on a.name=b.name

Related

How to combine two fields and flag them accordingly

I would like to know how to flag customers who did not purchase some items that are described by two fields (product name and product number). I was able to perform this query for customers that did purchase them, but not the opposite. Thank you in advance for your help!
Here is part of my SQL query.
Select customer_id, product_name, product_number
from table
where
((PRODUCT_NAME = 'LIAM' AND PRODUCT_NUMBER = '212') OR
(PRODUCT_NAME = 'ARRAY' AND PRODUCT_NUMBER = '325')
)
Here is an example:
1 LIAM 212
1 STACY 452
1 NEIL 789
1 LIAM 345
2 ROSE 234
2 LIAM 345
2 ARRAY 325
3 STACY 452
3 ARRAY 625
Query Result:
1 ARRAY 325
2 LIAM 212
3 ARRAY 325
3 LIAM 212
You seems want not exists :
select t.*
from table t
where not exists (select 1
from table t1
where t1.customer_id = t.customer_id and
t1.PRODUCT_NAME in ('LIAM', 'ARRAY')
);
I don't see any advantage using of both Product_name and Product_number in the where clause if they are defined unique in table.
By this way, you will get customer's who never purchased liam or array product.

Find rows for an id where value changes in any of the coloumn in sql

I have a table with say 10 columns where the unique identifier is id column.
I need print all the rows where value for any given id changes for any of the 10 coloums.
Eg:
Id name city state address mail phn number store no business name date
1 adam california ca acbb street xyz#gmail.com 12345 456 abc pvt 01-01-2017
1 adam newyork Ny avc xyz#gmail.com 12345 456 abc pvt 11-03-2018
1 adam newyork Ny avc xyz#gmail.com 12345 456 abcd pvt 24-03-2018
2 brian dallas Tx sasa sasa#gmail.com 21212 dsdssd ltd 01-01-2017
2 brian dallas Tx sasa sasa#gmail.com 232323 21212 dsdssd ltd 01-01-2017
3 donald dallas Tx qwer qwwqw#gmail.com 2121212 435345 sffsss ltd 23-01-2017
As shown above for id 1 there is a change from the first row to 2nd row on city state address so that should come .also for id 1 the 3rd row changes only business name so that should also be printed.
So basically for an id the status for that id before that date should be checked and if there is any change in any column it should be printed.
Same goes for id 2.For id 3 there is only one entry so that should not be printed.
The check needs to be done based on date for an id.
The data set that I have is in millions so would need a fine tuned query.
If you have a column for row number( for example ROWID), you can simply select all rows that has a pair (based on ID) in previous records and check if any of the last row columns differs from the first one:
select a.* from [yourTable] a
inner join [yourTable] b
on a.Id = b.Id where a.RowId > b.RowId
and (a.name <> b.name OR a.city <> b.city OR a.state <> b.state OR a.address <> b.address ... )

Simple nested query on the same table

So this is my table set up of 100k rows. I have around 30k rows which have the wrong dealer associated to it even though it refers to the same person but just a different bank designation. This happened due to a failure to port information accurately from a previous version of the database .
Table CustomerName
Name Bank Dealer SSN
John 1 ABC unique1
Mike 1 DEF unique2
Mike 2 wrong unique2
Mark 1 XYZ unique3
Mark 2 wrong unique3
Desired Table set up
Table CustomerName
Name Bank Dealer SSN
John 1 ABC unique1
Mike 1 DEF unique2
Mike 2 DEF unique2
Mark 1 XYZ unique3
Mark 2 XYZ unique3
I want to write a query which will target the rows (Bank 2 rows essentially) and change it to Bank 1 Dealer values. Is there a way to do it ? I'm using T-SQL ( SSMS 2016 )
EDIT :
SSN are like primary keys for the customer. every customer will have one ssn . the bank 2 is basically a delinquent account bank. A customer may or may not have a bank 2 account , but they'll have a bank 1 account. But my problem is that somehow the dealer didn't come through right for bank 2 and I need to update to the correct value
The question is which Dealer to use. Let me guess that it is the first one. You can use CTE and update to accomplish this:
with topudate as (
select cn.*,
max(case when bank = 1 then dealer end) over (partition by ssn) as dealer1
from customername cn
)
update toupdate
set dealer = dealer1
where dealer <> dealer1 or dealer is null;
If you have some other logic for getting the right name, then that would go in the case expression instead.
update bank2
set bank2.dealer = bank1.dealer
from CustomerName bank1
join CustomerName bank2
on bank2.SSN = bank1.SSN
and bank2.Bank = 2
and bank1.Bank = 1

Selecting only rows with the highest value of one field, grouped by another field

I have a table that has information structured like this:
ID Points Name School
1 123 James A
2 534 Henry B
3 56 Henry B
4 153 Chris B
5 95 Chris B
6 83 Chris B
7 421 James A
And I need to get out of a query the rows that have the same name, but only the highest points for each like this:
ID Points Name School
7 421 James A
2 534 Henry B
4 153 Chris B
Any ideas on how this could be accomplished with a query? I've spent way too much time trying to figure this out.
select name,school,max(points) from table group by name,school
That will give you the max points per name/school combination. Join it to itself if you want the ID:
select table.* from table inner join
(select name,school,max(points) as points from table group by name,school) a
on a.name = table.name and a.school = b.school and a.points = table.points
edit : sorry, this is a SQL solution...just saw the MSACCESS tag. Logic is right, but you'll need to convert to access syntax.
edit to correct the second query, missed a column inh my join
SELECT
(SELECT TOP 1 ID FROM Table
WHERE
Name = t.Name AND
School=t.School AND
Points=t.Points
) as Id, t.Name, t.Points, t.School
FROM
(SELECT Name, School, max(Points) as Points
FROM Table
GROUP BY Name, School) t

How to get the student academic progress?

course Table
course_code course_name credit_points_reqd
1 Comp Science 300
2 Soft Engineering 300
subject Table
subject_code subject_name credit_points
CS123 C Prog 15
CS124 COBOL 15
enrolment table
student_id student_name course_code subject_code Results
1 Lara Croft 1 CS123 70
1 Lara Croft 1 CS124 50
2 Tom Raider 2 CS123 60
2 Tom Raider 2 CS124 40
3 James Bond 1 CS123 NULL
3 James Bond 1 CS124 40
OUTPUT TABLE
student_name course_name credit_points_obt credit_points_reqd
Lara Croft Comp Science 30 300
Tom Raider Soft Engineering 15 300
I'm currently using TSQL. So here's the situation. I've prepared these tables to get the output like the way it i showed u up there. I need to calculate the credit points obtained. Credit points are achieved if the student receives > 50 for a subject they took. I want to ignore students that has not received any credit points at all (eg, James Bond is ignored as he has not achieved any points yet)
select student_name, course_name,credit_points_obt,credit_points_reqd
FROM enrolment (SELECT student_full_name, SUM(credit_points) AS credit_points_obt
FROM enrolment
GROUP BY student_id),
Totally stuck...I have no idea where to go now.
You can sum conditionally to get points for subject. If none are given result will be null, so you filter out those student/course pairs in having clause.
I've changed > 50 condition to >= 50 because your results contradict your requirements. Also, by the data I'd say that you have omitted student table for brewity, but if you haven't, it is a must.
Live test is # Sql Fiddle.
select enrolment.student_name,
course.course_name,
course.credit_points_reqd,
sum(case when enrolment.results >= 50
then subject.credit_points
end) credit_points_obt
FROM enrolment
inner join course
on enrolment.course_code = course.course_code
inner join subject
on enrolment.subject_code = subject.subject_code
group by enrolment.student_name,
course.course_name,
course.credit_points_reqd
having sum(case when enrolment.results >= 50
then subject.credit_points
end) is not null