Wednesday, March 28, 2012
looping with SQL
Below is an example of a dataset I build as a #wkfile. It consists of a
count/identity, Company, AccountNo, and Title. I’m trying to loop thru wi
th
SQL to pull out one occurrence of Company Name and AccountNo, into a 2nd
dataset. When there are more than one occurrence, the priority is first -
CEO’ OR like ‘%CEO%’, second - ‘CFO’ or like ‘%CFO%’, and if n
either of them
then take the first title.
id Company AccountNo Title
1 national Publishers A2053145611 CEO
2 (i)STRUCTURE, Inc A5051045506 CFO
3 (i)STRUCTURE, Inc 99091268226 Chief Executive Officer
4 (i)STRUCTURE, Inc A3013151569 Finance Director/CFO
5 (i)STRUCTURE, Inc 99091970756 President
6 (i)STRUCTURE, Inc 99091204766 President/CEO
7 (i)STRUCTURE, Inc 99091268239 Vice President
8 (i)STRUCTURE, Inc A5051045492 VP Finance & Service Management
9 (i)STRUCTURE, Inc A5051045541 VP Infrastructure Operations
10 (i)STRUCTURE, Inc A5051045455 VP Marketing
11 (i)STRUCTURE, Inc A5051045467 VP Sales
12 Andel Amba A3013151463 Finance Director/CFO
13 @.Global Inc A1022852020 President
14 @.plan, Inc. 99113038170 Chairman/CEO
15 @.plan, Inc. 99113038390 President/COO
16 @.plan, Inc. A0080460716 Vice President/CFO/CAO
17 @.radical.media, Inc. A4102749756 Chairman & CEO
18 @.radical.media, Inc. A4102749802 COO
19 @.radical.media, Inc. A4102749784 EVP
20 @.Road, Inc. A4071235030 CFOYou don't need to loop. It would have been nice if you supplied exact DDL
and real INSERT statements. Here's an untested solution:
select
o.*
from
MyTable
where
o.id in
(
select top 1
i.id
from
MyTable i
where
i.Company = o.Company
order by
case
when i.Title like '%CEO%' then 1
when i.Title like '%CFO%' then 2
else 3
end
, o.id
)
It's not clear what you mean by the "first" title, so I used id as the
tiebreaker.
Tom
----
Thomas A. Moreau, BSc, PhD, MCSE, MCDBA
SQL Server MVP
Columnist, SQL Server Professional
Toronto, ON Canada
www.pinpub.com
.
"Logger" <Logger@.discussions.microsoft.com> wrote in message
news:635B49E6-0714-46FA-997D-B44B4F1F0085@.microsoft.com...
Hopefully this is a better explanation of what I tried to explain earlier.
Below is an example of a dataset I build as a #wkfile. It consists of a
count/identity, Company, AccountNo, and Title. I’m trying to loop thru wi
th
SQL to pull out one occurrence of Company Name and AccountNo, into a 2nd
dataset. When there are more than one occurrence, the priority is first -
CEO’ OR like ‘%CEO%’, second - ‘CFO’ or like ‘%CFO%’, and if n
either of them
then take the first title.
id Company AccountNo Title
1 national Publishers A2053145611 CEO
2 (i)STRUCTURE, Inc A5051045506 CFO
3 (i)STRUCTURE, Inc 99091268226 Chief Executive Officer
4 (i)STRUCTURE, Inc A3013151569 Finance Director/CFO
5 (i)STRUCTURE, Inc 99091970756 President
6 (i)STRUCTURE, Inc 99091204766 President/CEO
7 (i)STRUCTURE, Inc 99091268239 Vice President
8 (i)STRUCTURE, Inc A5051045492 VP Finance & Service Management
9 (i)STRUCTURE, Inc A5051045541 VP Infrastructure Operations
10 (i)STRUCTURE, Inc A5051045455 VP Marketing
11 (i)STRUCTURE, Inc A5051045467 VP Sales
12 Andel Amba A3013151463 Finance Director/CFO
13 @.Global Inc A1022852020 President
14 @.plan, Inc. 99113038170 Chairman/CEO
15 @.plan, Inc. 99113038390 President/COO
16 @.plan, Inc. A0080460716 Vice President/CFO/CAO
17 @.radical.media, Inc. A4102749756 Chairman & CEO
18 @.radical.media, Inc. A4102749802 COO
19 @.radical.media, Inc. A4102749784 EVP
20 @.Road, Inc. A4071235030 CFO
looping to get correct data
I'd like to essentially loop through a SQL table to display the correct results. The workflow is the user query's the database and returns records (by property ID). In the return there are duplicate records being returned - in this case, two property owners returned with the same property ID.
How would I loop through the SQL statement in the application (code) to identify when the property id's are the same and display only one owner for that property?
Thanks!
You could do looping by using cursors by usually you should be able to formulate the query in a required way and it will be more performant.
How does the query look like? If it is simple enough you might achieve the result by using DISTINCT argument of the SELECT clause. Have a look at http://msdn2.microsoft.com/en-us/library/ms176104.aspx|||
I agree with Anton, if you formulate your query correctly you should not have to do this work on the client side. This also reduces internet traffic which could additionally speed up your end-to-end performance. If you could formulate the goal of your query as well as the structure of your tables and provide your current query, we could likely help you to write a SQL query that does the trick without this overhead.
Thanks,
John (MSFT)
looping to get correct data
I'd like to essentially loop through a SQL table to display the correct results. The workflow is the user query's the database and returns records (by property ID). In the return there are duplicate records being returned - in this case, two property owners returned with the same property ID.
How would I loop through the SQL statement in the application (code) to identify when the property id's are the same and display only one owner for that property?
Thanks!
You could do looping by using cursors by usually you should be able to formulate the query in a required way and it will be more performant.
How does the query look like? If it is simple enough you might achieve the result by using DISTINCT argument of the SELECT clause. Have a look at http://msdn2.microsoft.com/en-us/library/ms176104.aspx|||
I agree with Anton, if you formulate your query correctly you should not have to do this work on the client side. This also reduces internet traffic which could additionally speed up your end-to-end performance. If you could formulate the goal of your query as well as the structure of your tables and provide your current query, we could likely help you to write a SQL query that does the trick without this overhead.
Thanks,
John (MSFT)
looping thru a table and updating the contents
Hello, Its hard trying to explain this.
I have 3 tables
Table 1 is where the users are stored, each user has a username and a userrank
Table 2 is where the points that decides the userrank are stored
Table 3 contains the available userranks like this
Table 1 (user_list) looks briefly like this:
username nvarchar(20),
userrank int, -- Reference to Table3 id
... alot more fields
Table 2 (settings_profile) looks like this:
username nvarchar(20),
total_active_points int,
... some more fields
Table 3 (data_ranks) looks like this:
id int primary key auto inc,
rankname nvarchar(20),
min_pts int,
max_pts int
Points get added to table 2 whenever they do something that generates points on the site. Points also get withdrawn every 7 days, so a user can only collect points for 7 days, on the 8th day, all points he earned on the 1st day is reduced from the current points with this code:
WHILE(SELECT @.username= username, @.id= id, @.temp1= ap_sentmails, @.temp2= ap_createdthreads, @.temp3= ap_createdanswers, @.temp4= ap_signguestbook, @.temp5= ap_blogcomment, @.temp6= ap_createblogentry, @.temp7= ap_profilefirsttime, @.temp8= ap_profilephoto, @.temp9= ap_activateguestbook, @.temp10= ap_addnewfriend, @.temp11= ap_superguruvote, @.temp12= ap_forumtopicvote, @.temp13= ap_labervote, @.temp14= ap_funstuffitemvote, @.temp15= ap_movievote, @.temp16= ap_actorvote, @.temp17= ap_money_newWHERE(created<Dateadd(dd,-7, @.todaysdate))
BEGIN
SET @.sum= 0
SET @.sum= @.temp1+ @.temp2+ @.temp3+ @.temp4+ @.temp5+ @.temp6+ @.temp7+ @.temp8+ @.temp9+ @.temp10+ @.temp11+ @.temp12+ @.temp13+ @.temp14+ @.temp15+ @.temp16+ @.temp17
UPDATE settings_profileSET total_active_points= total_active_points- @.sumWHERE(username= @.username)
DELETEFROM konto_daylistWHERE(id= @.id)
END
Now my question is this, i want to loop thru the table A, collect all usernames inside of it, then run it against table b and table c to determine the current rank of the user.
Something like this...
DECLARE @.username nvarchar(20)
DECLARE @.pts int, @.rank int
...something that starts a loop thru table A (user_list) and get the username into @.username...
SELECT @.pts =total_active_points FROM settings_profile WHERE (username = @.username)
-- Determine the rank here, by compairing the points the user have against the pointstabel in table data_ranks
SELECT @.rank = id FROM data_ranks WHERE (pts_min => @.pts AND pts_max < @.pts)
UPDATE user_list SET rank = @.rank WHERE (username = @.username)
...next persion in the loop...
This SP runs once a day and will first reduce the points from 8days ago, then it will run thru all the users and determine their new rank...
But how do i loop thru all the users? with a cursor?
I don't have time to write this for you, but here's the line of attack to use:
Create and test a query that computes the the correct score for each user.
then, issue an update in this format:
update settings_profile
set total_active_points = ( the query from above where settings_profile.username = other_table.username)
|||
Hi, i dont truly understand what you meant. I can compute the score for each user If i have their username, thats why i need to create a loop that loops thru every post in table A, so that i can update every single post with the rank they earned from the points. I need to find someway to loop thru all posts.
|||No, you do not need to write a loop thru the users.
This is because the SQL Update statement provides an implied loop for you.
Example:
createtable xxx(idint, textvaluevarchar(20))
insertinto xxxvalues(1,'Nikki')
insertinto xxxvalues(2,'John')
update xxxset textvalue='Ginger'
select*from xxxYou will note that every xxx record now has Ginger in the textvalue column.
The update statement IS a loop!
And, while it is processing any given xxx record, it knows the value in each of that record's columns.
I do not have to hard-code the value that will be used to set textvalue with.
I can issue a query instead.
So, let's create a new table called nametable.
createtable nametable(idint,namevarchar(20))
insertinto nametablevalues(1,'Amber')
insertinto nametablevalues(2,'Tracy')
update xxx set textvalue = (select name from nametable where nametable.id = xxx.id)
select * from xxx
Note that the name for record 1 is now Amber and the name for record 2 is now Tracy
Hope that helps clarify things.
|||Hi,
Its working like a clock now, thanks for the explanation.
I build this line with the example code you sent, and its brilliant.
UPDATE profile_publicinfoSET userrank=(SELECT data_userrank.idFROM settings_profileINNERJOIN data_userrankON(data_userrank.pointsmin<= settings_profile.total_active_pointsAND data_userrank.pointsmax> settings_profile.total_active_points)WHERE(settings_profile.username= profile_publicinfo.username))
|||Great!
Now all you have to do is mark the thread as answered, so other folks don't spend their time trying to help you only to find out you don't need help anymore! :)
The key to being ultra-productive with SQL is to think in terms of "sets of data" instead of looping thru records of data one at a time.
|||
Then i just have to ask, is it possible to update several records with a IF statement?
Like this,
UPDATE clubsSET isactive=(IF(clubs_account.money-clubs_account.cost< 0SELECT 1) ELSE (SELECT 0)FROM clubs_account)
Thats money - expenses, if its less then 0, return a 1 otherwise return a 0
|||The SQL equivalent of an IF statement is a CASE statement.
But don't try to write it the way your if statement was coded.
Try this instead:
update clubs
set isactive = (select case clubs_account.money - clubs_account.cost < 0
when true then 1
else 0
end case
from clubs_account
where clubs_account.? = clubs.?
)
|||
Looks very good, but i just keeps getting an error when i tried it (i also tried to put () around the math calculations, but i still get the same result),
The clubs.inactive is a bit field if that is of any importance.
UPDATE clubsSET isactive=(SELECTCASE club_konto.money- club_konto.cost< 0WHEN trueTHEN 1ELSE 0ENDCASEFROM club_kontoWHERE club_konto.clubid= clubs.id)
Incorrect syntax near '<'.
|||bit fields are 1s and 0s, not true and false.
Also, I work in too many different languages. :( It's END, not END CASE.
createtable clubs(idint, isactivebit)
createtable club_konto( clubidint,moneyint, costint)
insertinto clubsvalues(1,1)
insertinto clubsvalues(2,1)
insertinto clubsvalues(3,0)
insertinto clubsvalues(4,0)
insertinto club_kontovalues(1,50,10)
insertinto club_kontovalues(2,10,50)
insertinto club_kontovalues(3,50,10)
insertinto club_kontovalues(4,10,50)
select*from clubs
select*from club_konto
UPDATE clubs
SET isactive=(SELECTCASEWHEN club_konto.money- club_konto.cost< 0THEN 1ELSE 0ENDFROM club_kontoWHERE club_konto.clubid= clubs.id)
select*from clubs
I have to caution you about this - the select statement used to populate the isactive column must NOT return more than one row of data.
If it can return more than one row, you need to change it so it only returns one row. So, if there can be two or more club_konto records per club, the query above will not work. Instead you would need it to be something like this:
UPDATE clubs
SET isactive=(SELECTCASEWHEN sum(club_konto.money)- sum(club_konto.cost)< 0THEN 1ELSE 0ENDFROM club_kontoWHERE club_konto.clubid= clubs.id)
|||I see that i need to learn alot more about how data is handeled inside MS SQL 2005, its working perfect with your example,
Thanks alot
(I have afew more SPs with While loops that i have to go thru now and see if i can upgrade them according to the new update way.)
Wednesday, March 21, 2012
Loop insert
I will do my best to explain my question:
I have a field called CUSTOMER which contains a number such as C00001,
C0002 etc.
However i now have a new field called XCUSTOMER which is the new number that they relate to.
CUSTOMER C00001 now relates to XCUSTOMER 493845.
CUSTOMER C00002 now relates to XCUSTOMER 494343.
Basically there are hundreds of these and i dont have the time to manually enter the data. I just want to say "where customer = C00001 then insert 49494 into XCUSTOMER and then loop through and insert them all.
My table is called CUSTOMERINFO.
If anyone could help it would be much apprieciated as it would save me so much time.
Thanks:)update customerinfo
set xcustomer = case customer
when 'c00001' then 493845
when 'c00001' then 494343
...
end