471,108 Members | 1,301 Online
Bytes | Software Development & Data Engineering Community
Post +

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 471,108 software developers and data experts.

Join stored procedures?

Hi all,

I have a challenge (not a problem). Simplifing it as far as i could, i
have this situation:

Table Persons
Id (PK)
Name

Table Scores
FK_Person (PK)
Period (PK)
Value

Now, i want to make a stored procedure that returns the scores for all
people in a certain period. So i have:

CREATE PROCEDURE [dbo].[ScorePerson]
(@Period Int)
AS
SELECT dbo.People.Name, dbo.Scores.[Value]
FROM dbo.People LEFT OUTER JOIN
dbo.Scores ON dbo.People.Id =
dbo.Scores.FK_person
WHERE dbo.Scores.Period = @Period
GO

BUT: if a person has no score for a certain period, he will not show
up in the result set at all, but i do want him to. So what i need to
do is first get the subset for a period from the table Scores and THEN
Left join that to the persons, so i always get all persons and only a
value for the the score if there is one.

How can i do this? I could store the results in a temporary table but
that just feels 'unpure', wrong. Is there any way i can get this in a
single pass? Can i for example join two stored procedures with
parameters together in another SP that passes these params on to them?

TIA,

Gert-Jan
Jul 20 '05 #1
7 6925
If you have no Periods table, you can get the list of periods based on your
Scores table. Of course, this technique will only return periods with at
least one row in the Scores table so you'll need a Periods table if you need
to include periods with no scores. Below is an example:

SELECT
dbo.People.Name,
dbo.Scores.[Value]
FROM dbo.People
LEFT JOIN dbo.Scores ON
dbo.People.Id = dbo.Scores.FK_person AND
dbo.Scores.Period = @Period
CROSS JOIN
(SELECT DISTINCT Period
FROM Scores) AS Periods
WHERE Periods.Period = @Period

--
Hope this helps.

Dan Guzman
SQL Server MVP

"G.J. v.d. Kamp" <gj******@hotmail.com> wrote in message
news:d4**************************@posting.google.c om...
Hi all,

I have a challenge (not a problem). Simplifing it as far as i could, i
have this situation:

Table Persons
Id (PK)
Name

Table Scores
FK_Person (PK)
Period (PK)
Value

Now, i want to make a stored procedure that returns the scores for all
people in a certain period. So i have:

CREATE PROCEDURE [dbo].[ScorePerson]
(@Period Int)
AS
SELECT dbo.People.Name, dbo.Scores.[Value]
FROM dbo.People LEFT OUTER JOIN
dbo.Scores ON dbo.People.Id =
dbo.Scores.FK_person
WHERE dbo.Scores.Period = @Period
GO

BUT: if a person has no score for a certain period, he will not show
up in the result set at all, but i do want him to. So what i need to
do is first get the subset for a period from the table Scores and THEN
Left join that to the persons, so i always get all persons and only a
value for the the score if there is one.

How can i do this? I could store the results in a temporary table but
that just feels 'unpure', wrong. Is there any way i can get this in a
single pass? Can i for example join two stored procedures with
parameters together in another SP that passes these params on to them?

TIA,

Gert-Jan

Jul 20 '05 #2
Please post DDL, so that people do not have to guess what the keys,
constraints, Declarative Referential Integrity, datatypes, etc. in
your schema are. Sample data is also a good idea, along with clear
specifications.

You also need to read a basic book on data modeling and the ISO-11179
naming conventions. How many different names did you post for the same
data element? Why are tables that share a data element modeled as if
they had no DRI relationships in your personal pseudo-code?

CREATE TABLE Persons
(player_id INTEGER NOT NULL PRIMARY KEY,
name CHAR(35) NOT NULL);

CREATE TABLE Games
(player_id INTEGER NOT NULL
REFERENCES Persons (player_id),
period_nbr INTEGER NOT NULL,
score INTEGER NOT NULL CHECK (score >= 0));
I want to make a stored procedure that returns the scores for all

people in a certain period. <<

Why do you still think in procedural terms in a non-procedural
language? Why not a VIEW?

CREATE VIEW TotalScores (player_name, period_nbr, score_tot)
AS
SELECT P.player_name, G.period_nbr, SUM(G.score_tot)
FROM Persons AS P
LEFT OUTER JOIN
Games AS G
ON P.player_id = G.player_id
GROUP BY player_id, period_nbr;

Then you can use this query

SELECT player_name, @my_period_nbr, score_tot
FROM TotalScores
WHERE @my_period_nbr = period_nbr;

A zero means he played and did not score; a NULL means he did not play
at all.
Jul 20 '05 #3
On 25 Nov 2004 10:39:49 -0800, --CELKO-- wrote:

(snip)
CREATE VIEW TotalScores (player_name, period_nbr, score_tot)
AS
SELECT P.player_name, G.period_nbr, SUM(G.score_tot)
FROM Persons AS P
LEFT OUTER JOIN
Games AS G
ON P.player_id = G.player_id
GROUP BY player_id, period_nbr;
Hi Joe,

Maybe you should have tested this before posting!

Server: Msg 170, Level 15, State 1, Procedure TotalScores, Line 8
Line 8: Incorrect syntax near ';'.

(Okay, this is buggy behaviour of SQL Server - but this IS a SQL Server
group, after all!)

Remove the semicolon; retry:

Server: Msg 207, Level 16, State 3, Procedure TotalScores, Line 3
Invalid column name 'player_name'.
Server: Msg 207, Level 16, State 1, Procedure TotalScores, Line 3
Invalid column name 'score_tot'.
Server: Msg 209, Level 16, State 1, Procedure TotalScores, Line 3
Ambiguous column name 'player_id'.

Change player_name to name and score_tot to score in the SELECT and add P.
in front of player_id in the GROUP BY; retry:

Server: Msg 8120, Level 16, State 1, Procedure TotalScores, Line 3
Column 'P.name' is invalid in the select list because it is not contained
in either an aggregate function or the GROUP BY clause.

Okay, add P.name to the group by (or enclose it in an aggregate function),
retry and finally the view is made (whew!).

Then you can use this query

SELECT player_name, @my_period_nbr, score_tot
FROM TotalScores
WHERE @my_period_nbr = period_nbr;

A zero means he played and did not score; a NULL means he did not play
at all.


Let's enter some data to test it. Two persons (Joe and Hugo). Both have a
score in period 1, Joe has a score in period 2 and Hugo in period 3.

insert Persons values(1,'Joe')
insert Persons values(2,'Hugo')
insert Games values (1, 1, 1)
insert Games values (2, 1, 2)
insert Games values (1, 2, 3)
insert Games values (2, 3, 0)
GO
declare @my_period_nbr int
set @my_period_nbr = 1
SELECT player_name, @my_period_nbr, score_tot
FROM TotalScores
WHERE @my_period_nbr = period_nbr;
set @my_period_nbr = 2
SELECT player_name, @my_period_nbr, score_tot
FROM TotalScores
WHERE @my_period_nbr = period_nbr;
set @my_period_nbr = 3
SELECT player_name, @my_period_nbr, score_tot
FROM TotalScores
WHERE @my_period_nbr = period_nbr;

Does this return the data that the poster asked for? Does this return Hugo
in period 2 and Joe in period 3, even though they have no score in that
period?

Unfortunately - no.

Best, Hugo
--

(Remove _NO_ and _SPAM_ to get my e-mail address)
Jul 20 '05 #4
On 25 Nov 2004 07:18:55 -0800, G.J. v.d. Kamp wrote:

(snip)
BUT: if a person has no score for a certain period, he will not show
up in the result set at all, but i do want him to. So what i need to
do is first get the subset for a period from the table Scores and THEN
Left join that to the persons, so i always get all persons and only a
value for the the score if there is one.


Hi Gert-Jan,

This is actually lots simpler than you think!

SELECT dbo.People.Name, dbo.Scores.[Value]
FROM dbo.People LEFT OUTER JOIN
dbo.Scores ON dbo.People.Id =
dbo.Scores.FK_person
AND dbo.Scores.Period = @Period

(The only change is to move the filter condition for period to the join
condition!!)

Best, Hugo
--

(Remove _NO_ and _SPAM_ to get my e-mail address)
Jul 20 '05 #5
Hi all,

Thanks everyone for your time.

Dan, works like a charm, thanks! It obviously does help to have a
thorough foundation in math.

Celko, i only described the problem in a generic way, i thought it
would be a common problem a person more experienced than me would
recognize. (and they did). Also, a view doesn't take parameters as far
as i know. THe point about SQL not being a procedural language is
usually a good one, personally i don't think very highly of people who
break out cursors for the simplest of inserts. But i don't think it's
just in this case. Thanks anyway.

But of course first prize goes to Hugo for the lean of going about it.
I like lean, and now i like Hugo (In a friendly way, don't worry!)
Thanks!

Regards GJ

Hugo Kornelis <hugo@pe_NO_rFact.in_SPAM_fo> wrote in message news:<h5********************************@4ax.com>. ..
On 25 Nov 2004 07:18:55 -0800, G.J. v.d. Kamp wrote:

(snip)
BUT: if a person has no score for a certain period, he will not show
up in the result set at all, but i do want him to. So what i need to
do is first get the subset for a period from the table Scores and THEN
Left join that to the persons, so i always get all persons and only a
value for the the score if there is one.


Hi Gert-Jan,

This is actually lots simpler than you think!

SELECT dbo.People.Name, dbo.Scores.[Value]
FROM dbo.People LEFT OUTER JOIN
dbo.Scores ON dbo.People.Id =
dbo.Scores.FK_person
AND dbo.Scores.Period = @Period

(The only change is to move the filter condition for period to the join
condition!!)

Best, Hugo

Jul 20 '05 #6
Celko,

Your solution will probably work as well, but i just like to keap my
asp code as neat as possible, so i move all the logic to the
SQL-server as much as i can. Also, in my real world problem, it would
theoretically be possible to have a zero score as a value.

But thanks anyway.

Regards GJ
jc*******@earthlink.net (--CELKO--) wrote in message news:<18**************************@posting.google. com>...
Please post DDL, so that people do not have to guess what the keys,
constraints, Declarative Referential Integrity, datatypes, etc. in
your schema are. Sample data is also a good idea, along with clear
specifications.

You also need to read a basic book on data modeling and the ISO-11179
naming conventions. How many different names did you post for the same
data element? Why are tables that share a data element modeled as if
they had no DRI relationships in your personal pseudo-code?

CREATE TABLE Persons
(player_id INTEGER NOT NULL PRIMARY KEY,
name CHAR(35) NOT NULL);

CREATE TABLE Games
(player_id INTEGER NOT NULL
REFERENCES Persons (player_id),
period_nbr INTEGER NOT NULL,
score INTEGER NOT NULL CHECK (score >= 0));
I want to make a stored procedure that returns the scores for all

people in a certain period. <<

Why do you still think in procedural terms in a non-procedural
language? Why not a VIEW?

CREATE VIEW TotalScores (player_name, period_nbr, score_tot)
AS
SELECT P.player_name, G.period_nbr, SUM(G.score_tot)
FROM Persons AS P
LEFT OUTER JOIN
Games AS G
ON P.player_id = G.player_id
GROUP BY player_id, period_nbr;

Then you can use this query

SELECT player_name, @my_period_nbr, score_tot
FROM TotalScores
WHERE @my_period_nbr = period_nbr;

A zero means he played and did not score; a NULL means he did not play
at all.

Jul 20 '05 #7
-P-
"G.J. v.d. Kamp" <gj******@hotmail.com> wrote in message news:d4**************************@posting.google.c om...
Also, a view doesn't take parameters as far
as i know.


Views don't take parameters in the same way as procedures and functions, but you can still use your parameters...

Select *
from myView
where myView.col1 = @myParameter ;

The view is created without the parameter @myParameter, but it's easy to write queries on the view that use them.

--
Paul Horan
Sr. Architect
VCI Springfield, Mass
www.vcisolutions.com

Jul 20 '05 #8

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

5 posts views Thread by Rob Wire | last post: by
2 posts views Thread by Jon.Hakkinen | last post: by

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.