0

i have the following tables:

projects: id, name, language
          1 |test | php
          2 |test | java
          3 |hello| php


attrs:  id, name,      value,   tb1_id
        1  | status    | finish | 1
        2  | reference | 2      | 1

I need a query to select all projects, which have a attribute "reference" to another project and "status" finish.

example output:

id, name      
1 |test 

Could you help me?

4
  • BTW, the id column in your attrs table appears to serve no purpose Commented Dec 6, 2013 at 9:06
  • @Strawberry A unique primary key is if nothing else often useful for more complex queries, such as removing duplicate attributes. Commented Dec 6, 2013 at 9:15
  • @JoachimIsaksson A compound natural PK can be formed on the entity (tb1_id) and attribute (name), in which case the scenario you describe would not occur. In any case, where a surrogate key is used, best practice requires a natural UNIQUE (compound) key to be formed alongside. Commented Dec 6, 2013 at 9:42
  • @Strawberry I see what you're saying, and you have a good point in that a natural key is very (more) useful in that case. I guess I'm just a surrogate key type person, I've almost always lived to regret skimping on them :) Commented Dec 6, 2013 at 9:57

4 Answers 4

1

You can either:

  • group the joined tables, filtering such groups with suitable aggregate functions within the HAVING clause:

    SELECT   projects.id, projects.name
    FROM     projects
        JOIN attrs ON attrs.tb1_id = projects.id
    GROUP BY projects.id
    HAVING   SUM(attrs.name='reference')
         AND SUM(attrs.name='status' AND attrs.value='finish')
    
  • or else join attrs multiple times:

    SELECT   p.id, p.name
    FROM     projects AS p
        JOIN attrs    AS r ON  r.tb1_id = p.id
                           AND r.name   = 'reference'
        JOIN attrs    AS s ON  s.tb1_id = p.id
                           AND s.name   = 'status'
    WHERE    s.value = 'finish'
    
Sign up to request clarification or add additional context in comments.

2 Comments

your 1. query works, can you edit so, so i get also the id of the references project?
@AlexanderG.: If you want that, you're probably better off using the second query (and adding r.value to the select list).
1
SELECT P.id, P.name
FROM projects P inner join attrs A on P.id = a.tb1_id
WHERE (A.name = 'status' AND value = 'finish')
UNION
SELECT P.id, P.name
FROM attrs A INNER JOIN projects P ON A.value = P.id
WHERE A.name='reference'

See the result in this fiddle

5 Comments

I think it should be A.value='finish'
Because value is not an ambiguous column (e.g. it only occurs in the attrs table) you can put value='finish' instead of A.value='finish'. But it works both ways
The problem is, it's possible that other attributes, e.g. name="created" also can the value ="finish". It's possible to say only name="status" should be value="finish"?
I updated my answer, I misread your question. The query now results in all the projects which have an attribute with a name status and the value finish
You're not taking the reference attribute into account.
0

Try this:

SELECT p.id, p.name
FROM projects p 
INNER JOIN (SELECT tb1_id, MAX(IF(a.name = 'status', a.value, '')) attrStatus, MAX(IF(a.name = 'reference', a.value, '')) attrReference
                FROM attrs a GROUP BY tb1_id) A ON p.id = A.tb1_id AND A.attrStatus = 'finish' 
WHERE EXISTS (SELECT 1 FROM projects p1 WHERE A.attrReference = p1.id)

Check the SQL FIDDLE DEMO

OUTPUT

| ID | NAME |
|----|------|
|  1 | test |

Comments

0

You'll need to join attrs twice, once for each attribute;

SELECT p.*, ref_attr.value reference FROM projects p
JOIN attrs ref_attr  ON ref_attr.tb1_id = p.id
                    AND ref_attr.name = 'reference'
JOIN attrs stat_attr ON stat_attr.tb1_id = p.id
                    AND stat_attr.name = 'status'
                    AND stat_attr.value = 'finish'

An SQLfiddle to test with.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.