473,386 Members | 1,706 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

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

Query to reduce a 1-to-n relationship to 1-to-1

My problem is as follows:
I have a customer table and an address table. A customer can have 0, 1 or many addresses. The query result I'm trying to get produces 1 and only 1 row for each customer, with either 1 address or null's for the appropriate address fields. Here's some simple sql to demonstrate:

create table test_customer (custid char(10), custname char(20))
create table test_address (custid char(10), addrid char(10), city char(20))

insert into test_customer values ('ID1', 'Cust1')
insert into test_customer values ('ID2', 'Cust2')
insert into test_customer values ('ID3', 'Cust3')
insert into test_customer values ('ID4', 'Cust4')

insert into test_address values ('ID1', 'Addr1a', 'Paris')
insert into test_address values ('ID1', 'Addr1b', 'London')
insert into test_address values ('ID2', 'Addr2a', 'New York')
insert into test_address values ('ID3', 'Addr3a', 'Tokyo')

select a.custid, a.custname, b.addrid, b.city
from test_customer a, test_address b
where a.custid *= b.custid

The select produces this result:
ID1 Cust1 Addr1a Paris
ID1 Cust1 Addr1b London
ID2 Cust2 Addr2a New York
ID3 Cust3 Addr3a Tokyo
ID4 Cust4 NULL NULL

The result I'm trying to achieve is:
ID1 Cust1 Addr1a Paris
ID2 Cust2 Addr2a New York
ID3 Cust3 Addr3a Tokyo
ID4 Cust4 NULL NULL

When I try to do a subquery to produce the 1-1 customer/address join, and then do an outer query to add the city, I get the infamous "not permitted outer join" error message:

select a.custid, a.custname, b.addrid, b.city
from test_customer a, test_address b,
(select c.custid, min(d.addrid) sub1addr
from test_customer c, test_address d
where c.custid *= d.custid
group by c.custid) as sub1
where a.custid *= b.custid
and a.custid *= sub1.custid
and b.addrid *= sub1.sub1addr

Output:
Server: Msg 301, Level 16, State 1, Line 1
Query contains an outer-join request that is not permitted.

The subtle change of trying to make the last line an inner join gives me this error:
select a.custid, a.custname, b.addrid, b.city
from test_customer a, test_address b,
(select c.custid, min(d.addrid) sub1addr
from test_customer c, test_address d
where c.custid *= d.custid
group by c.custid) as sub1
where a.custid *= b.custid
and a.custid *= sub1.custid
and b.addrid = sub1.sub1addr

Server: Msg 303, Level 16, State 1, Line 1
The table 'test_address' is an inner member of an outer-join clause. This is not allowed if the table also participates in a regular join clause.

Thanks for any suggestions. Suggestions such as changing the design aren't feasible, as this is a simplified version of a db that's in production.
Aug 24 '07 #1
4 2204
Jim Doherty
897 Expert 512MB
My problem is as follows:
I have a customer table and an address table. A customer can have 0, 1 or many addresses. The query result I'm trying to get produces 1 and only 1 row for each customer, with either 1 address or null's for the appropriate address fields. Here's some simple sql to demonstrate:

create table test_customer (custid char(10), custname char(20))
create table test_address (custid char(10), addrid char(10), city char(20))

insert into test_customer values ('ID1', 'Cust1')
insert into test_customer values ('ID2', 'Cust2')
insert into test_customer values ('ID3', 'Cust3')
insert into test_customer values ('ID4', 'Cust4')

insert into test_address values ('ID1', 'Addr1a', 'Paris')
insert into test_address values ('ID1', 'Addr1b', 'London')
insert into test_address values ('ID2', 'Addr2a', 'New York')
insert into test_address values ('ID3', 'Addr3a', 'Tokyo')

select a.custid, a.custname, b.addrid, b.city
from test_customer a, test_address b
where a.custid *= b.custid

The select produces this result:
ID1 Cust1 Addr1a Paris
ID1 Cust1 Addr1b London
ID2 Cust2 Addr2a New York
ID3 Cust3 Addr3a Tokyo
ID4 Cust4 NULL NULL

The result I'm trying to achieve is:
ID1 Cust1 Addr1a Paris
ID2 Cust2 Addr2a New York
ID3 Cust3 Addr3a Tokyo
ID4 Cust4 NULL NULL

When I try to do a subquery to produce the 1-1 customer/address join, and then do an outer query to add the city, I get the infamous "not permitted outer join" error message:

select a.custid, a.custname, b.addrid, b.city
from test_customer a, test_address b,
(select c.custid, min(d.addrid) sub1addr
from test_customer c, test_address d
where c.custid *= d.custid
group by c.custid) as sub1
where a.custid *= b.custid
and a.custid *= sub1.custid
and b.addrid *= sub1.sub1addr

Output:
Server: Msg 301, Level 16, State 1, Line 1
Query contains an outer-join request that is not permitted.

The subtle change of trying to make the last line an inner join gives me this error:
select a.custid, a.custname, b.addrid, b.city
from test_customer a, test_address b,
(select c.custid, min(d.addrid) sub1addr
from test_customer c, test_address d
where c.custid *= d.custid
group by c.custid) as sub1
where a.custid *= b.custid
and a.custid *= sub1.custid
and b.addrid = sub1.sub1addr

Server: Msg 303, Level 16, State 1, Line 1
The table 'test_address' is an inner member of an outer-join clause. This is not allowed if the table also participates in a regular join clause.

Thanks for any suggestions. Suggestions such as changing the design aren't feasible, as this is a simplified version of a db that's in production.

Ok no design change so lets go with what we have here well from what I can see its a question of returning the ONE address for each customer even if they have no address... I've utilised a standard UDF function for that to return a concatenated single return value for the address which you can always parse out to extra columns once you see the return dataset in analyser or opening the view. Here is the script pasted below to create the view and the UDF

--Try this for good measure the UDF function returns the top 1 address
--for the CustID passed in we then SELECT out using the view after that
--the view produces a column of the concatenated address fields essentialthe
--requirements of the single return value the UDF demands
--you can then parse out the elements of the concatenation to extra columns
--I did not know your needs on that so I'll leave that one with you

CREATE FUNCTION UDF_CustomerAddress
( @CustID char(10) )
RETURNS varchar(255)
AS
BEGIN
RETURN (
SELECT TOP 1
COALESCE (LTRIM(RTRIM(Addrid)), '')+' '+ COALESCE (LTRIM(RTRIM(City)), '') as address
FROM test_Address
WHERE CustID = @CustID)
END
Go

CREATE VIEW dbo.vw_CustomersSingleAddress
AS
SELECT custid, custname, dbo.UDF_CustomerAddress(custid) AS [Customer Address]
FROM dbo.test_customer
GO
Aug 24 '07 #2
Thanks Jim. This works, although I was hoping that the answer wouldn't involve having to parse the string returned by the function (I need to have these values available for loading into another table). Any other ideas out there?

Ok no design change so lets go with what we have here well from what I can see its a question of returning the ONE address for each customer even if they have no address... I've utilised a standard UDF function for that to return a concatenated single return value for the address which you can always parse out to extra columns once you see the return dataset in analyser or opening the view. Here is the script pasted below to create the view and the UDF

--Try this for good measure the UDF function returns the top 1 address
--for the CustID passed in we then SELECT out using the view after that
--the view produces a column of the concatenated address fields essentialthe
--requirements of the single return value the UDF demands
--you can then parse out the elements of the concatenation to extra columns
--I did not know your needs on that so I'll leave that one with you

CREATE FUNCTION UDF_CustomerAddress
( @CustID char(10) )
RETURNS varchar(255)
AS
BEGIN
RETURN (
SELECT TOP 1
COALESCE (LTRIM(RTRIM(Addrid)), '')+' '+ COALESCE (LTRIM(RTRIM(City)), '') as address
FROM test_Address
WHERE CustID = @CustID)
END
Go

CREATE VIEW dbo.vw_CustomersSingleAddress
AS
SELECT custid, custname, dbo.UDF_CustomerAddress(custid) AS [Customer Address]
FROM dbo.test_customer
GO
Aug 24 '07 #3
azimmer
200 Expert 100+
Thanks Jim. This works, although I was hoping that the answer wouldn't involve having to parse the string returned by the function (I need to have these values available for loading into another table). Any other ideas out there?
How 'bout this one?
Expand|Select|Wrap|Line Numbers
  1. select t.custid, t.custname, addr.addrid, addr.city
  2. from
  3. (
  4. select a.custid, a.custname, min(b.addrid) as minaddrid
  5. from test_customer a left outer join test_address b on a.custid = b.custid
  6. group by a.custid, a.custname
  7. ) as t left outer join test_address addr on t.minaddrid=addr.addrid
  8.  
NB: Do not use the WHERE syntax for outer joins -- MSSQL hates it...
Aug 25 '07 #4
How 'bout this one?
Expand|Select|Wrap|Line Numbers
  1. select t.custid, t.custname, addr.addrid, addr.city
  2. from
  3. (
  4. select a.custid, a.custname, min(b.addrid) as minaddrid
  5. from test_customer a left outer join test_address b on a.custid = b.custid
  6. group by a.custid, a.custname
  7. ) as t left outer join test_address addr on t.minaddrid=addr.addrid
  8.  
NB: Do not use the WHERE syntax for outer joins -- MSSQL hates it...
Thanks, this is a MUCH more workable solution!
Aug 27 '07 #5

Sign in to post your reply or Sign up for a free account.

Similar topics

226
by: Stephen C. Waterbury | last post by:
This seems like it ought to work, according to the description of reduce(), but it doesn't. Is this a bug, or am I missing something? Python 2.3.2 (#1, Oct 20 2003, 01:04:35) on linux2 Type...
8
by: Andante.in.Blue | last post by:
Hello, I have just inherited a legacy Access 97 database. While going through it, I noticed something strange... its Relationships window (the one accessed by Tools --> Relationships) is almost...
1
by: KLAU | last post by:
I have a field that retrieves information from an expression in a query. I have used a DLookup function to get the calculated field from the query. However, the relationship is 1-to-many so one...
0
by: leavandor | last post by:
I am trying to design a query that works with a relationship between a Table and a Query. I am comparing a value in the table with a computed value inside the query. The reason for this is that...
5
by: MattPF | last post by:
I have a table that is -- 30 Megabytes 90,000 rows ~65 columns My query goes SELECT city FROM table WHERE zip = 90210; It will then find about 10 matching records.
2
by: Eckhart | last post by:
Dear All, Plz help me in optimising the following query, Reduce repeatable reads from the table via select ,ythe table sare not having referntial integrity constarints ,relations CREATE proc...
1
by: crazdandconfusd | last post by:
I have a database with two tables I use for shipping information. One is for if I'm only shipping one item and the other is for a back page of a report for when I ship multiple items. If I'm...
5
by: themastertaylor | last post by:
I've got a system to manage various quotes for building materials for a number of sites. i want a query to produce a report that shows me who HASN'T quoted for which sites. basically so i can...
16
by: BNW | last post by:
I need help in finding out why I am not getting any data in my query. When I select all the fields in one table in my query grid and run it, the data is there. However, when I try to do it...
2
mreed72
by: mreed72 | last post by:
I have a problem and can't get clear enough to figure it out. 2 tables in my database are related to each other. table1 = contacts table2 = Jobs both are a 1to1 relation, using the standard...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...

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.