Moose
Moose

Reputation: 202

SQL join two tables using value from one as column name for other

I'm a bit stumped on a query I need to write for work. I have the following two tables:

|===============Patterns==============|
|type       | bucket_id | description |
|-----------------------|-------------|
|pattern a  | 1         |  Email      |
|pattern b  | 2         |  Phone      |


|==========Results============|
|id     | buc_1     | buc_2   |
|-----------------------------|
|123    | pass      |         |
|124    | pass      |fail     |

In the results table, I can see that entity 124 failed a validation check in buc_2. Looking at the patterns table, I can see bucket 2 belongs to pattern b (bucket_id corresponds to the column name in the results table), so entity 124 failed phone validation. But how do I write a query that joins these two tables on the value of one of the columns? Limitations to how this query is going to be called will most likely prevent me from using any cursors.

Upvotes: 1

Views: 3217

Answers (3)

Sylvain Leroux
Sylvain Leroux

Reputation: 51980

An other approach if you are using Oracle ≥ 11g, would be to use the UNPIVOT operation. This will translate columns to rows at query execution:

select * from Results
unpivot ("result" for "bucket_id" in ("buc_1" as 1, "buc_2" as 2))
join Patterns
using("bucket_id")
where "result" = 'fail';

Unfortunately, you still have to hard-code the various column names.

See http://sqlfiddle.com/#!4/a3eae/17

Upvotes: 0

Sylvain Leroux
Sylvain Leroux

Reputation: 51980

Some crude solutions:

SELECT "id", "description" FROM
Results JOIN Patterns
ON "buc_1" = 'fail' AND "bucket_id" = 1

union all 

SELECT "id", "description" FROM
Results JOIN Patterns
ON "buc_2" = 'fail' AND "bucket_id" = 2

Or, with a very probably better execution plan:

SELECT "id", "description" FROM
Results JOIN Patterns
ON "buc_1" = 'fail' AND "bucket_id" = 1
OR "buc_2" = 'fail' AND "bucket_id" = 2;

This will report all failure descriptions for each id having a fail case in bucket 1 or 2.

See http://sqlfiddle.com/#!4/a3eae/8 for a live example


That being said, the right solution would be probably to change your schema to something more manageable. Say by using an association table to store each failed test -- as you have in fact here a many to many relationship.

Upvotes: 1

eco
eco

Reputation: 1364

It looks to me that what you really want to know is the description(in your example Phone) of a Pattern entry given the condition that the bucket failed. Regardless of the specific example you have you want a solution that fulfills that condition, not just your particular example.

I agree with the comment above. Your bucket entries should be tuples(rows) and not arguments, and also you should share the ids on each table so you can actually join them. For example, Consider adding a bucket column and index their number then just add ONE result column to store the state. Like this:

  |===============Patterns==============|
  |type       | bucket_id | description |
  |-----------------------|-------------|
  |pattern a  | 1         |  Email      |
  |pattern b  | 2         |  Phone      |


  |==========Results====================|
  |entity_id     | bucket_id    |status |
  |-------------------------------------|
  |123           | 1            |pass   |
  |124           | 1            |pass   |
  |123           | 2            |       |
  |124           | 2            |fail   |

1.-Use an Inner Join: http://www.w3schools.com/sql/sql_join_inner.asp and the WHERE clause to filter only those buckets that failed:

2.-Would this example help?

 SELECT Patterns.type, Patterns.description, Results.entity_id,Results.status
 INNER JOIN Results
 ON
 Patterns.bucket_id=Results.bucket_id
 WHERE
 Results.status=fail

Lastly, I would also add a primary_key column to each table to make sure indexing is faster for each unique combination.

Thanks!

Upvotes: 0

Related Questions