tags:

views:

260

answers:

3
SELECT (b.descr || ' - ' || c.descr) description
  FROM tbl1 a LEFT JOIN tbl2 b ON a.ACCOUNT = b.ACCOUNT 
       LEFT JOIN tbl3 c ON a.product = c.product
 WHERE a.descr50 = ' ' ;

table1 has only 7622 rows with descr50 = ' ' but this select is returning 7649 rows. Could you please help me in this? thanks in advance

+3  A: 

table1 may have only 7622 rows, but if tbl2 has more than one row with the same ACCOUNT value, or if tbl3 has more than one row where the product matches, you'll get more rows in the result set. You're effectively "multiplying" each of the tables.


EDIT: OK, an example.

Suppose tbl1 has only 1 row, and that the "ACCOUNT" is 1 and the "product" is 2. (I don't know what actual values are in the table; it does not matter).

Now suppose that tbl2 has 2 rows where "ACCOUNT" is 1. Straight away, you're going to get at least 2 rows in your results, because tbl1 will match 2 rows in tbl2.

Now if tbl3 has 2 rows where "product" is 2, you'll get 4 rows in the results, because each of the 2 results above will match 2 rows in tbl3.

So hopefully you can see why you're getting more rows than you expected. What you choose to do about it is a different matter, and depends on whether the fact that there are multiple matches in tbl2 and tbl3 indicate a problem with the data.

Gary McGill
Hi McGill, Thanks for your answer. I have checked the same query by creating a sample table it is working fine. I have compared the output with the actual table and found 27 are extra. I dont know how. Please help me in this.
Prem
+1 my answer exactly, but you beat me to it :)
Roee Adler
@Prem - presumably your sample table didn't have the same data! The query *will* "work fine" if there's only one matching row in each of tbl2 and tbl3.
Gary McGill
Is there anyother solution for this? Please guide me in this if you have any. Thanks in advance.
Prem
+1  A: 

When you JOIN two or more table together, you effectively get a cartesian product for these tables to which a filter stated in the JOIN condition is applied.

This is more obvious when you use an obsolete implicit JOIN syntax.

The LEFT JOIN guarantees that you get no less rows than the leftmost table contains, i. e. each row from the leftmost table is returned at least once.

You can still get more rows, if the filter is not a one-to-one row mapping.

In your case:

SELECT  (b.descr || ' - ' || c.descr) description
FROM    tbl1 a
LEFT JOIN
        tbl2 b
ON      b.ACCOUNT = a.ACCOUNT
LEFT JOIN
        tbl3 c
ON      c.product = a.product
WHERE  a.descr50 = ' '

either acccount or product are not unique in b or c.

For these rows:

a.account

1
2
3

b.account  b.description

1          Account 1
2          Account 2 - old
2          Account 2 - new

, the JOIN will return the following:

a.account b.account b.description

1         1          Account 1
2         2          Account 2 - old
2         2          Account 2 - new
3         NULL       NULL

, giving you more rows than either of the tables contains.

To just pick the first matching description from either table, use this:

SELECT  (
        SELECT  FIRST_VALUE(descr) OVER (ORDER BY descr)
        FROM    tbl2 b
        WHERE   b.account = a.account
                AND rownum = 1
        ) || ' - ' ||
        (
        SELECT  FIRST_VALUE(descr) OVER (ORDER BY descr)
        FROM    tbl3 c
        WHERE   c.product= a.product
                AND rownum = 1
        ) description
FROM    tbl1 a
WHERE   a.descr50 = ' '

To update, just wrap the query into an inline view:

UPDATE  (
        SELECT  (
                SELECT  FIRST_VALUE(descr) OVER (ORDER BY descr)
                FROM    tbl2 b
                WHERE   b.account = a.account
                        AND rownum = 1
                ) || ' - ' ||
                (
                SELECT  FIRST_VALUE(descr) OVER (ORDER BY descr)
                FROM    tbl3 c
                WHERE   c.product= a.product
                        AND rownum = 1
                ) description
        FROM    tbl1 a
        WHERE   a.descr50 = ' '
        )
SET     descr50 = description
Quassnoi
Thanks for your explanation. My requiremetn is to fill the table1 field called description by concatinating the description from the table2 and table3. But the common field between 1 and 2 is account and 1 and 3 is product. Can you please help me in this ?
Prem
I cant update directly, i have to check it then only i can update. That y i am using select to get the values but its is more that the values in the table1. but only 27.
Prem
@Prem: I updated the post with sample data. Given that `b` contains more than one description for account `2`, which description you want account `2` to have?
Quassnoi
Thank for your reply Quassnoi. Did you get my requirement? i need all the three accounts to be captured by my join. So its the second one .If you are not clear with my req , i'll explain it clearly . thanks in advance.
Prem
@Quass Ai sorry mate, i need the first one alone. If the account is not there in the b means no need to include that.... i am little confused in this. If you get my req i think you can give me a solution.
Prem
@Prem: could you please look at my sample data (the data in my post) and tell what description you want to get for account `2`?
Quassnoi
@Prem: what `RDBMS` are you using? I can tell how to do what you want but the answer will totally depend on the `SQL` dialect.
Quassnoi
I am using oracle.
Prem
@Quass I want to update the table 1 field called "Descr50" by concatinating the descr values from table2 and table 3. common field between 1 and 2 is account , and for the 1 and 3 is product. table 2 has account with same as well as table 3 has same product name for many rows. table1.descr = table2.descr + tabl3.descr. This is thing what i have to do. Please help me in this.
Prem
I am leaving for the day Quass. see you tomorrow, if you get anything please post it to me. Thanks for the timely help mate bye.
Prem
@Prem: See post update.
Quassnoi
@Quass : Where is the Post update , Quass?
Prem
@Prem: in the post. Did you try the last query?
Quassnoi
@ Quassnoi . The last query is fine quass, but how to update this.
Prem
@Prem: see the post update.
Quassnoi
+1  A: 

As a test to determine where the additional rows are coming from, try adding more fields to your SELECT statement from the joined tables and look at the data returned.

One option to correct the issue is to group your joined tables after joining them:

SELECT (b.descr || ' - ' || c.descr) description
    FROM tbl1 a 
    LEFT JOIN tbl2 b ON a.ACCOUNT = b.ACCOUNT 
    LEFT JOIN tbl3 c ON a.product = c.product
    WHERE a.descr50 = ' '
    GROUP BY b.descr, c.descr

Another option would be to group your tbl2 and tbl3 tables before joining them:

SELECT (b.descr || ' - ' || c.descr) description
    FROM tbl1 a 
    LEFT JOIN 
    (
        SELECT descr, ACCOUNT 
            FROM tbl2 
            GROUP BY descr, ACCOUNT
    ) AS b
        ON a.ACCOUNT = b.ACCOUNT
    LEFT JOIN 
    (
        SELECT descr, product 
            FROM tbl3 
            GROUP BY descr, product 
    ) AS c
        ON a.product = c.product 
    WHERE a.descr50 = ' '
Chris Porter
Thanks for your explanation. My requiremetn is to fill the table1 field called description by concatinating the description from the table2 and table3. But the common field between 1 and 2 is account and 1 and 3 is product. Can you please help me in this ?
Prem
I cant update directly, i have to check it then only i can update. That y i am using select to get the values but its is more that the values in the table1. but only 27
Prem
Are the queries I posted still returning 27 extra rows? If so you have more than one value of descr in tbl2 for a given ACCOUNT or in tbl3 for a given product. How do you want to handle this? Do you need to chose a value to use or is a random selection ok?
Chris Porter
@Chris porter. I want to update a table with descr by contcating the descr value from other two tables. i got the output by select statement , while i am trying to update it. its showing error, sub query contain more than one row.
Prem
That is exactly what I was trying to say. For your sub-query to complain about more than 1 result, you must have more than 1 combination of descr from b + c that you are trying to use to update your other table. How do you want to handle this? Do you want to "ignore it" and force the update multiple times with the last time being the "correct" update? Do you want to use the most recent entry (assuming b and/or c have a date stamp)? I suggest you update the question with your current query so our answers can better apply to your situation.
Chris Porter