1

I'm trying to map from a string value to a list of ids to use in an IN clause and haven't found a way to make it work yet. Hopefully the query I've tried so far will make this clear:

SELECT COUNT(*) FROM events
WHERE level_id IN (
  SELECT
  CASE
      WHEN skill_level='Beginner' THEN (SELECT id from levels WHERE code IN ('L1', 'L2'))
      WHEN skill_level='Intermediate' THEN (SELECT id from levels WHERE code IN ('L3', 'L4'))
      WHEN skill_level='Advanced' THEN (SELECT id from levels WHERE code IN ('L5', 'L6'))
  END ids
  FROM users WHERE id=2
)

Which could simplify for a 'Beginner' skill level user to this:

SELECT COUNT(*) FROM events WHERE level_id IN (1, 2)

I created a fiddle to test this here.

I get the error "more than one row returned by a subquery used as an expression" when I try this. I've tried a number of permutations including the array() operator but I always get one error or another.

Maybe I'm fundamentally going about this the wrong way. If anyone can suggest a fix for my query, or another way to accomplish the same thing it would be greatly appreciated.

2
  • 2
    Sample data would really help your question here. Commented Jun 28, 2021 at 13:42
  • There is sample data in the linked fiddle. Commented Jun 29, 2021 at 13:01

4 Answers 4

2

Don't use a case like that. Use simpler boolean logic:

SELECT COUNT(*)
FROM events
WHERE (skill_level = 'Beginner' AND level_id IN ('L1', 'L2')) OR
      (skill_level = 'Intermediate' AND level_id IN ('L3', 'L4')) OR
      (skill_level = 'Advanced' AND level_id IN ('L5', 'L6'));

I'm not sure what this logic is for:

FROM users WHERE id = 2

Your question does not explain that.

Sign up to request clarification or add additional context in comments.

2 Comments

"skill_level" is in the users table, while "code" is in the levels table. Please see the fiddle for clarification.
@GregButler . . . You have already been asked for sample data. The question should clarify such things.
1

Error "more than one row returned by a subquery used as an expression" arises because of:

    WHEN skill_level=... THEN (SELECT id from levels WHERE code IN (...))

inside CASE statement.

UPDATE

Maybe the best would be to use suggestion of @gordon-linoff



SELECT COUNT(*) 
FROM 
    events E
    JOIN levels L ON E.level_id = L.id
    JOIN users U ON 
        ( U.skill_level='Beginner' AND  L.code IN ('L1', 'L2'))
        OR  (U.skill_level='Intermediate' AND L.code IN ('L3', 'L4'))
        OR  (U.skill_level='Advanced' AND L.code IN ('L5', 'L6'))
   WHERE
       U.id = 2

https://www.db-fiddle.com/f/tP8MPuy2ks3Zfuo9jSAmJA/4

Previous answer

Fix would be to use CASE-statement as predicate for JOIN:

SELECT COUNT(*) FROM events 
WHERE
    level_id IN (
      SELECT 
              L.id
          FROM 
              users U
              JOIN levels L ON
                CASE
                    WHEN skill_level='Beginner' THEN  code IN ('L1', 'L2')
                    WHEN skill_level='Intermediate' THEN  code IN ('L3', 'L4')
                    WHEN skill_level='Advanced' THEN code IN ('L5', 'L6')
                END 
          WHERE
              U.id = 2
    )

Look on: https://www.db-fiddle.com/f/tP8MPuy2ks3Zfuo9jSAmJA/1

Comments

1

I found a way that works in Postgresql 11. Didn't work in 9.4, but as I am working in 11, that's fine. I don't know if it's a good way, but it does work. Alex Yu's answer might be better but I haven't done any performance testing. Here it is for what it's worth:

SELECT COUNT(*) FROM events
WHERE level_id = ANY(ARRAY(
SELECT
CASE
    WHEN skill_level='Beginner' THEN ARRAY(SELECT id from levels WHERE code IN ('L1', 'L2'))
    WHEN skill_level='Intermediate' THEN ARRAY(SELECT id from levels WHERE code IN ('L3', 'L4'))
    WHEN skill_level='Advanced' THEN ARRAY(SELECT id from levels WHERE code IN ('L5', 'L6'))
END ids
FROM users WHERE id=2
));
count
3

View on DB Fiddle

2 Comments

You found a good answer. Essentially it's the same as mine but has less letters. Actually @GordonLinoff maybe gave the best answer
But maybe the best answer would be: db-fiddle.com/f/tP8MPuy2ks3Zfuo9jSAmJA/4
0

It misses a key in levels table. You should add a skill_level column to link skill_level users. Then it becomes easier to make your query.

See the example here

1 Comment

Thanks for the suggestion but I have to work with the tables as they are currently structured. This is a simplified example that demonstrates my problem, not my actual real-world tables.

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.