Reputation: 61
To the very basic query
SELECT id, column1, column2
FROM table1
WHERE id IN ("id1", "id2", "id3")
in which the the arguments in the where statement are passed as a variable, I need to return values also for rows where the id doesn't exist. In general, this is a very similar problem as outlined here: SQL: How to return an non-existing row? However, multiple parameters are in the WHERE statement
The result right now when id2 doesn't exist:
-------------------------------
| id | column1 | column2 |
-------------------------------
| id1 | some text | some text |
| id3 | some text | some text |
-------------------------------
Desired outcome when id2 doesn't exist
-----------------------------------
| id | column1 | column2 |
-----------------------------------
| id1 | some text | some text |
| id2 | placeholder | placeholder |
| id3 | some text | some text |
-----------------------------------
My first thought was to create a temporary table and join it against the query. Unfortunately, I don't have the rights to create any kind of temporary table so that I am limited to a SELECT statement.
Is there way to do that in with a SQL SELECT query?
Edit: Indeed, the above mentioned is a hypothetical situation. In the WHERE clause can be hundreds of ids where the amount of missing in unknown.
Upvotes: 6
Views: 1864
Reputation: 107347
Project a derived table containing all the candidate ids you want, then left join to it:
select ids.id, coalesce(table1.column1,'placeholder') From (Select 'id1' as id Union Select 'id2' Union Select 'id3') ids left join table1 on ids.id1 = table1.id1 and table1.id in (...);
If you are producing the list of candidate ids
from an external source (e.g. an application), you could insert the ids into a temporary table and then join to it (MySql doesn't support table variables yet).
Upvotes: 0
Reputation: 523
Create a stored procedure that would take as input id1, id2 and so on...
DELIMITER //
CREATE PROCEDURE P1(IN p_in varchar(5))
BEGIN
DECLARE count integer;
SELECT count(id) INTO count FROM TABLE1
WHERE id = p_in;
IF count = 1 THEN
SELECT * from table1 where id = p_in;
ELSE
select p_id, 'some text', 'some text';
END IF;
END//
DELIMITER ;
The call the procedure to get desired output..
CALL P1('id1');
CALL P2('id2');
.. and so on from your program..
Upvotes: 0
Reputation: 562731
You can do a derived table to create something like a temp table, but it can only be used for this one query:
SELECT t.id, COALESCE(t.column1, _dflt.column1) AS column1
FROM (
SELECT 'id1' AS id, 'placeholder text 1' as column1
UNION ALL
SELECT 'id2', 'placeholder text 3'
UNION ALL
SELECT 'id3', 'placeholder text 3'
) AS _dflt
LEFT OUTER JOIN table1 t USING (id);
Re comments:
I just tested the method above on MySQL 5.6.15 to see how many distinct SELECTs I can get with a series of UNION ALLs, one row per SELECT.
I got the derived table to return 5332 rows, but I think I could go higher if I had more RAM.
If I try one more UNION ALL, I get: ERROR 1064 (42000): memory exhausted near '' at line 10665
. I only have 2.0GB of RAM configured on this VM.
It doesn't matter how many ids are unknown for this solution to work. Just put them all in the derived table. By using LEFT OUTER JOIN
, it automatically finds those that exist in your table1, and for the ones that are missing, the entry from the derived table will be matched up with NULLs.
The COALESCE() function returns its first non-null argument, so it'll use columns from the matched rows if those are present. Where none is found, it'll default to the columns in the derived table.
Upvotes: 4