Copy rows of data in SQL Server - sql

Please help me come up with a solution for the situation being explained below:
ID name address age hobby GPA
---------------------------------------------------------
101 James 100 Garfield St 21 reading 3.13
101 James 100 Garfield St 21 writing 2.63
101 James 100 Garfield St 21 running 3.81
109 Tom 19 Lily Ave 19 dating 3.54
109 Tom 20 Lily Ave 19 climbing 2.76
109 Tom 21 Lily Ave 19 watching 3.91
I want to copy the set of rows with the same ID (eg. 101) and assign each set a State abbreviation(s) by running a single sql query. For instance: adding states CA, NJ, and DE to rows with an ID of 101, the result set is expected to look like this:
ID name address age hobby GPA state
-----------------------------------------------------------------------
101 James 100 Garfield St 21 reading 3.13 CA
101 James 100 Garfield St 21 writing 2.63 CA
101 James 100 Garfield St 21 running 3.81 CA
101 James 100 Garfield St 21 reading 3.13 NJ
101 James 100 Garfield St 21 writing 2.63 NJ
101 James 100 Garfield St 21 running 3.81 NJ
101 James 100 Garfield St 21 reading 3.13 DE
101 James 100 Garfield St 21 writing 2.63 DE
101 James 100 Garfield St 21 running 3.81 DE
Please keep in mind that everything else remains the same way as they were before the addition of the state abbreviations. Also assume I have more than three states to add and integrate to the query, say, I have all 50 states. Thank you for your time and effort in advance!

This should produce that result set:
select x.*, y.st
from tbl x
join
(select 'CA' as st union all
select 'NJ' union all
select 'DE') y
where x.id = 101

Create a new table with IDs and States
ID ST
101 CA
101 NJ
101 DE
109 ..
then join that on your table
SELECT t.*, s.st
FROM tbl t
JOIN states s ON t.id = s.id

Related

How do I generate a crosswalk ID between two SQL tables

I have a SQL table consisting of names, addresses and some associated numerical data paired with a code. The table is structured such that each number-code pair has its own row with redundant address info. abbreviated version below, let's call it tblPeopleData
Name Address ArbitraryCode ArbitraryData
----------------------------------------------------------------------------
John Adams 45 Main St, Rochester NY a 111
John Adams 45 Main St, Rochester NY a 231
John Adams 45 Main St, Rochester NY a 123
John Adams 45 Main St, Rochester NY b 111
John Adams 45 Main St, Rochester NY c 111
John Adams 45 Main St, Rochester NY d 123
John Adams 45 Main St, Rochester NY d 124
Jane McArthur 12 1st Ave, Chicago IL a 111
Jane McArthur 12 1st Ave, Chicago IL a 231
Jane McArthur 12 1st Ave, Chicago IL a 123
Jane McArthur 12 1st Ave, Chicago IL b 111
Jane McArthur 12 1st Ave, Chicago IL c 111
Jane McArthur 12 1st Ave, Chicago IL e 123
Jane McArthur 12 1st Ave, Chicago IL e 124
My problem is that this table is absolutely massive (~10 million rows) and I'm trying to split it up to make traversal less staggeringly sluggish.
What I've done so far is to make a table of just addresses, using something like:
SELECT DISTINCT Address FROM tblPeopleData (etc.)
Leaving me with:
Name Address
------------------------------------------
John Adams 45 Main St, Rochester NY
Jane McArthur 12 1st Ave, Chicago IL
...just a list of addresses. I want to be able to look up each address and see which names reside at that address, so I assigned each address a UniqueID, such that now I have (this table is around ~500,000 rows in my dataset):
Name Address AddressID
--------------------------------------------------------
John Adams 45 Main St, Rochester NY 000001
Jane McArthur 12 1st Ave, Chicago IL 000002
In order to be able to look up people by address though, I need this AddressID field added to tblPeopleData, such that each address in tblPeopleData is associated with its AddressID and this is added to every row, such that I would have:
Name Address ArbitraryCode ArbitraryData AddressID
----------------------------------------------------------------------------------------
John Adams 45 Main St, Rochester NY a 111 00001
John Adams 45 Main St, Rochester NY a 231 00001
John Adams 45 Main St, Rochester NY a 123 00001
John Adams 45 Main St, Rochester NY b 111 00001
John Adams 45 Main St, Rochester NY c 111 00001
John Adams 45 Main St, Rochester NY d 123 00001
John Adams 45 Main St, Rochester NY d 124 00001
Jane McArthur 12 1st Ave, Chicago IL a 111 00002
Jane McArthur 12 1st Ave, Chicago IL a 231 00002
Jane McArthur 12 1st Ave, Chicago IL a 123 00002
Jane McArthur 12 1st Ave, Chicago IL b 111 00002
Jane McArthur 12 1st Ave, Chicago IL c 111 00002
Jane McArthur 12 1st Ave, Chicago IL e 123 00002
Jane McArthur 12 1st Ave, Chicago IL e 124 00002
How do I make this jump from having UniqueIDs for AddressID in my unique addresses table, to adding these all to each row with a corresponding address back in my tbPeopleData?
Just backfill the calculated AddressID back to tblPeopleData - you can combine an UPDATE with a FROM (like you would do in a select)
UPDATE tblPeopleData
SET AddressID = a.AddressID
FROM tblPeopleData pd
INNER JOIN tblAddressData a
ON pd.Address = a.Address
You would alter the table to have the address id:
alter table tblPeopleData add AddressId int references Address(AddressId);
Then you can update the value using a JOIN:
update tblPeopleData pd JOIN
Address a
ON pd.Address = a.Address
pd.AddressId = a.AddressId;
You will definitely want an index on Address(Address) for this.
Then, you can drop the old column:
alter table drop column Address;
Note:
It might be faster to save the results in a temporary table, because the update is going to generate lots and lots of log records. For this, truncate the original table, and re-load the data:
SELECT . . . , a.AddressId
INTO tmp_tblPeopleData
FROM tblPeopleData pd JOIN
Address a
ON pd.Address = a.Address;
TRUNCATE TABLE tblPeopleData;
INSERT INTO tblPeopleData( . . .)
SELECT . . .
FROM tmp_tblPeopleData;

Max from Query from Select data

I am pretty new to SQL and need some help with a query. I am trying the find the MAX TradeCodeID using the following query. It is not returning the data I need. It is pretty much returning t.
select distinct
t.useremployeeid,
max(t.usertradeID),
t.Projectfullname,
t.userfirstname + ' '+ t.userlastname as GreatestPM
from
(select distinct
users.UserTradeId, UserEmployeeID, UserFirstName, UserLastName,
ProjectFullName, ProjectManager,
max(ScheduleDate) as LastDate
from
schedules
left outer join
users on ScheduleUserID = UserID
left outer join
Phases on SchedulePhaseID = PhaseID
left outer join
Projects on phases.ProjectID = projects.ProjectID
left outer join
UserTrades on UserTrades.UserTradeID = Users.UserTradeID
where
users.useractive = 1
and users.useremployeeid <> 0
and users.usertradeid between 21 and 24
and projectfullname is not null
group by
users.UserTradeid, UserEmployeeID, UserFirstName, UserLastName,
ProjectFullName, ProjectManager
having
max(scheduledate) > getdate() ) t
group by
t.projectfullname, t.userfirstname,t.userlastname, UserEmployeeID
order by
t.projectfullname
From the following data set:
useremployeeid UserTradeID Projectfullname GreatestPM
--------------------------------------------------------------------------------
12121 22 162331.05 John Smith
25487 21 166324.1 Chuck Norris
45639 21 166324.1 Brad Pitt
35789 23 166324.1 John Doe
15697 24 166324.1 Matt Damon
28957 23 166324.1 Taylor Swift
76985 21 166324.1 Tony Romo
25496 21 166324.1 George Strait
85695 22 167091.1 Robin Roberts
75632 21 167091.1 Scott Smith
66897 22 1663341.01 Garth Brooks
58766 21 1663341.01 Travis Tritt
37895 21 1663341.01 Sara Roberts
95687 21 1663352.01 Justin Timberlake
85697 24 1663352.01 Sally Walker
I am looking to get the following results:
useremployeeid UserTradeID Projectfullname GreatestPM
----------------------------------------------------------
12121 22 162331.05 John Smith
15697 24 166324.1 Matt Damon
85695 22 167091.1 Robin Roberts
66897 22 1663341.01 Garth Brooks
85697 24 1663352.01 Sally Walker
Thank you for the help.

SQL logic for getting records in a single row for a unique id

![Cognost reports studio Query Explorer]
Below is the snapshot of a table.
**Acctno ClientNo ClientName PrimaryOffId SecondaryOffID**
101 11111 ABC corp 3 Not Defined
102 11116 XYZ Inc 5 Not Defined
103 11113 PQRS Corp 2 9
104 55555 Food LLC 4 11
105 99999 Kwlg Co 1 Not Defined
106 99999 Kwlg Co 1 Not Defined
107 11112 LMN Corp Not Defined 6
108 11112 LMN Corp Not Defined 6
109 11115 Sleep Co 4 10
110 44444 Cool Co Not Defined 8
111 11114 Sail LLC 3 Not Defined
112 66666 Fun Inc 1 Not Defined
113 88888 Job LLC 5 12
114 22222 Acc Co Not Defined Not Defined
115 77777 Good Corp 2 Not Defined
116 33333 City LLC Not Defined 7
117 33333 City LLC Not Defined 7
118 33333 City LLC Not Defined 7
119 11111 ABC corp 3 Not Defined
I want to replace PrimaryOffID and SecondaryOffID with their Names coming from this table
EmpID Names
1 Cathy
2 Chris
3 John
4 Kevin
5 Mark
6 Celine
7 Jane
8 Phil
9 Jess
10 Jose
11 Nick
12 Rosy
The Result should look like this: Notice that, If Cathy is the PrimaryOfficer, she can't be the Secondary Officer and vice versa. This logic is applicable for all the Names
Acctno ClientNo Client Name PrimOffName SecondaryOffName
101 11111 ABC corp John Not Defined
102 11116 XYZ Inc Mark Not Defined
103 11113 PQRS Corp Chris Jess
104 55555 Food LLC Kevin Nick
105 99999 Kwlg Co Cathy Not Defined
106 99999 Kwlg Co Cathy Not Defined
107 11112 LMN Corp Not Defined Celine
108 11112 LMN Corp Not Defined Celine
109 11115 Sleep Co Kevin Jose
110 44444 Cool Co Not Defined Phil
111 11114 Sail LLC John Not Defined
112 66666 Fun Inc Cathy Not Defined
113 88888 Job LLC Mark Rosy
114 22222 Acc Co Not Defined Not Defined
115 77777 Good Corp Chris Not Defined
116 33333 City LLC Not Defined Jane
117 33333 City LLC Not Defined Jane
118 33333 City LLC Not Defined Jane
119 11111 ABC corp John Not Defined
But Instead it looks like this:
Acctno ClientNo ClientName PrimOffName SecondaryOffName
101 11111 ABC corp John Not Defined
102 11116 XYZ Inc Mark Not Defined
103 11113 PQRS Corp Chris Not Defined
103 11113 PQRS Corp Not Defined Jess
104 55555 Food LLC Kevin Not Defined
104 55555 Food LLC Not Defined Nick
105 99999 Kwlg Co Cathy Not Defined
106 99999 Kwlg Co Cathy Not Defined
107 11112 LMN Corp Not Defined Celine
108 11112 LMN Corp Not Defined Celine
109 11115 Sleep Co Kevin Not Defined
109 11115 Sleep Co Not Defined Jose
110 44444 Cool Co Not Defined Phil
111 11114 Sail LLC John Not Defined
112 66666 Fun Inc Cathy Not Defined
113 88888 Job LLC Mark Not Defined
113 88888 Job LLC Not Defined Rosy
114 22222 Acc Co Not Defined Not Defined
115 77777 Good Corp Chris Not Defined
116 33333 City LLC Not Defined jane
117 33333 City LLC Not Defined jane
118 33333 City LLC Not Defined jane
119 11111 ABC corp John Not Defined
Notice that, now the Acctno is no more unique, Where ever the Names should have been in both the fields together, it separates and gives the output in the next row creating multiple records. i tried various options but it didn't work. Please be aware, that I am creating this report in Cognos Studio. Please suggest the possible query to get the desired result. Thanks in Advance. Appreciate your help.
You don't state which version of Cognos you're using. "Cognos Studio" is ambiguous. I'm most familiar with 8.4.1, but even then you don't say if you're trying to define this in the Cognos model, Query Studio, Event Studio or Report Studio.
Second, you should always show what you've got so far when asking questions on StackOverflow. People want to see what you have done to show you want to fix, not repeat the lion's share of the work. That's why you got downvotes.
As far as plain SQL, you'll want to do this:
SELECT a.Acctno, a.ClientNo, a.ClientName, coalesce(e1.Names,'Not Defined') "PrimaryOffName", coalesce(e2.Names,'Not Defined') "SecondaryOffName"
FROM Account a
LEFT OUTER JOIN Emp e1
ON t.PrimaryOffID = e1.EmpID
LEFT OUTER JOIN Emp e2
ON t.PrimaryOffID = e2.EmpID
I made up table names. You can do this in Report Studio by creating two queries for Emp and outer joining them in succession to the Account query.
If you're able to, you'll want to move the OffID fields to a separate juntion table and remove them from the Account table. You can then create a Status field or flag in that junction table that identifies primary and secondary.

SQL Select Distinct returning duplicates

I am trying to return the country, golfer name, golfer age, and average drive for the golfers with the highest average drive from each country.
However I am getting a result set with duplicates of the same country. What am I doing wrong? here is my code:
select distinct country, name, age, avgdrive
from pga.golfers S1
inner join
(select max(avgdrive) as MaxDrive
from pga.golfers
group by country) S2
on S1.avgdrive = s2.MaxDrive
order by avgdrive;
These are some of the results I've been getting back, I should only be getting 15 rows, but instead I'm getting 20:
COUN NAME AGE AVGDRIVE
---- ------------------------------ ---------- ----------
Can Mike Weir 35 279.9
T&T Stephen Ames 41 285.8
USA Tim Petrovic 39 285.8
Ger Bernhard Langer 47 289.3
Swe Fredrik Jacobson 30 290
Jpn Ryuji Imada 28 290
Kor K.J. Choi 37 290.4
Eng Greg Owen 33 291.8
Ire Padraig Harrington 33 291.8
USA Scott McCarron 40 291.8
Eng Justin Rose 25 293.1
Ind Arjun Atwal 32 293.7
USA John Rollins 30 293.7
NIr Darren Clarke 37 294
Swe Daniel Chopra 31 297.2
Aus Adam Scott 25 300.6
Fij Vijay Singh 42 300.7
Spn Sergio Garcia 25 301.9
SAf Ernie Els 35 302.9
USA Tiger Woods 29 315.2
You are missing a join condition:
select s1.country, s1.name, s1.age, s1.avgdrive
from pga.golfers S1 inner join
(select country, max(avgdrive) as MaxDrive
from pga.golfers
group by country
) S2
on S1.avgdrive = s2.MaxDrive and s1.country = s2.country
order by s1.avgdrive;
Your problem is that some people in one country have the same average as the best in another country.
DISTINCT eliminated duplicate rows, not values in some fields.
To get a list of countries with ages, names, and max drives, you would need to group the whole select by country.

SQL Server: Merge Data Rows in single table in output

I have a SQL Server table with the following fields and sample data:
ID Name Address Age
23052-PF Peter Timbuktu 25
23052-D1 Jane Paris 22
23052-D2 David London 24
23050-PF Sam Beijing 22
23051-PF Nancy NYC 26
23051-D1 Carson Cali 22
23056-PF Grace LA 28
23056-D1 Smith Boston 23
23056-D2 Mark Adelaide 26
23056-D3 Hose Mexico 25
23056-D4 Mandy Victoria 24
Each ID with -PF is unique in the table.
Each ID with the -Dx is related to the same ID with the -PF.
Each ID with -PF may have 0 or more IDs with -Dx.
The maximum number of -Dx rows for a given -PF is 9.
i.e. an ID 11111-PF can have 11111-D1, 11111-D2, 11111-D3 up to 11111-D9.
Output expected for above sample data:
ID ID (without suffix) PF_Name PF_Address PF_Age D_Name D_Address D_Age
23052-PF 23052 Peter Timbuktu 25 Jane Paris 22
23052-PF 23052 Peter Timbuktu 25 David London 24
23050-PF 23050 Sam Beijing 22 NULL NULL NULL
23051-PF 23051 Nancy NYC 26 Carson Cali 22
23056-PF 23056 Grace LA 28 Smith Boston 23
23056-PF 23056 Grace LA 28 Mark Adelaide 26
23056-PF 23056 Grace LA 28 Hose Mexico 25
23056-PF 23056 Grace LA 28 Mandy Victoria 24
I need to be able to join the -PF and -Dx as above.
If a -PF has 0 Dx rows, then D_Name, D_Address and D_Age columns in the output should return NULL.
If a -PF has one or more Dx rows, then PF_Name, PF_Address and PF_Age should repeat for each row in the output and D_Name, D_Address and D_Age should contain the values from each related Dx row.
Need to use MSSQL.
Query should not use views or create additional tables.
Thanks for all your help!
select
pf.ID,
pf.IDNum,
pf.Name as PF_Name,
pf.Address as PF_Address,
pf.Age as PF_Age,
dx.Name as D_Name,
dx.Address as D_Address,
dx.Age as D_Age
from
(
select
ID, left(ID, 5) as IDNum, Name, Address, Age
from
mytable
where
right(ID, 3) = '-PF'
) pf
left outer join
(
select
ID, left(ID, 5) as IDNum, Name, Address, Age
from
mytable
where
right(ID, 3) != '-PF'
) dx
on pf.IDNum = dx.IDNum
SqlFiddle demo: http://sqlfiddle.com/#!6/dfdbb/1
SELECT t1.ID, LEFT(t1.ID,5) "ID (without Suffix)",
t1.Name "PF_Name", t1.Address "PF_Address", t1.Age "PF_Age",
t2.Name "D_Name", t2.Address "D_Address", t2.Age "D_Age"
FROM PFTable t1
LEFT JOIN PFTable t2 on LEFT(t1.ID,5) = LEFT(t2.ID,5)
WHERE RIGHT(t1.ID,2) = 'PF'