WHERE IN with subquery NOT WORKING as expected - mysql

I am trying to get result from my categories table using the parent path i have created.
When i launch the request WHERE IN with manual data it's working perfectly.
When i am trying the same request dynamically with subquery, i got only one result instead of 4 expected.
I do not understand why, can you help me ?
http://sqlfiddle.com/#!2/88b68/6
/*Working query*/
SELECT t.id_categorie FROM t
WHERE t.id_categorie IN (1396,1399,1403,1412)
/*Not working by subquery ??*/
SELECT cat.id_categorie FROM t as cat
WHERE
cat.id_categorie IN (SELECT REPLACE(t.path,'.',',') FROM t WHERE t.id_categorie = 1412)
Thanks by advance,
Regards,

Using in with a comma delimited list does not do what you want. Even when you use a subquery. You could try this:
SELECT cat.id_categorie
FROM t cat
WHERE EXISTS (SELECT 1
FROM t
WHERE t.id_categorie = 1412 AND
find_in_set(cat.id_categorie, REPLACE(t.path, '.', ',')) > 0
);
I'm not sure what your data looks like or even what this query is supposed to be doing (it seems strange that the subquery is on the same table as the outer query). Usually, though, you want to store things in tables rather than delimited lists. You see, SQL has a built-in data structure for lists. It is called a table.

The reason this does not work is that your inner SELECT produces a single comma-separated VARCHAR, rather than four individual integers.
In MySQL you can use find_in_set, like this:
SELECT cat.id_categorie FROM t as cat
WHERE find_in_set(cat.id_categorie, (
SELECT REPLACE(t.path,'.',',')
FROM t WHERE t.id_categorie = 1412))
What I did was replacing the IN expression in your query with a call to find_in_set, leaving everything else the same.
Demo
However, this solution is fundamentally flawed, because it stores multiple values in a single column to represent a many-to-many relationship. A better approach to implementing this requirement is using a separate table that connects rows of the table to their related rows.

Related

SQL using IN when value stores in another ROW

So i have a few numbers that i stored into row as (1,2,3) ( lets name it as "ids" in table "some" )
And i using LEFT JOIN in another query to get some row using this field as ids
But when i wrote
LEFT JOIN sometable AS st WHERE some2.id IN some.ids
i get an error.
How i can use it correct, or maybe another way to realize that
thanks
Storing comma-delimited lists of integers as a string is the wrong way to store things. You should be using a junction table.
If you are stuck with this format and don't care about performance, you can use find_in_set():
where find_in_set(some2.id, some.ids) > 0

select all from one table but compare to multiple tables

Hello I have the following query:
SELECT *
FROM ams.TestResultHiPot_Archive,ams.unit u
WHERE timestamp >='3/16/2017 20:39 ' AND timestamp <= '3/17/2017, 20:39' AND LOWER(line_code)=LOWER('aac04')
AND LOWER(unitmodelnumber) like LOWER('%%%') AND unitmodelnumber != 'VTI' and u.serial_num=unitserialnumber and u.date_deleted is null
this table has many fields so I want to stay away from hard coding each field AND also this structure works for multiple tables.
The only issue I am having is some of the comparison items are in the units table so I want to visit that tablet to compare and if it matches then include that record in my result from the ORIGINALTEST RESULTS ARCHIVE table NOT the units table.
the main issue I am seeing is that the select * is causing both tables to return all of their fields.
Is there a way to use select * ,and still compare 2 tables but get the columns ONLY from one table ?
I have tried right join, left join, inner join but nothing seems to work, they all return all the columns from both tables, maybe I have done it incorrectly, or maybe this can't be done?
I also thought maybe doing like a query that selects all the table fields and then storing them in an array and passing that array as my select parameters, that way I am passing the exact needed parameters without hardcoding (since I would always consult the table) but that seems like it would take longer since pgsql is slower. Any suggestions are greatly appreciated.
select ams.TestResultHiPot_Archive.*

SELECT no rows and no columns?

Is it possible to write a SELECT statement, which returns dataset with zero rows and zero columns?
A dataset will always have at least 1 column, even if it contains no data.
SELECT NULL;
EDIT:
As pointed out by #eggyal , above syntax will return a null row.
His query select null from dual where false; wont return a row.
Not possible in my opinion. You will get at least one column, but no rows.
Select null from yourTable where 1 = 2;
This works for postgresql:
create table test22 ();
select * from test22;
it's normally used for Creating empty Table from an Existing Table
CREATE TABLE NEW_TABLE_NAME AS
SELECT *
FROM EXISTING_TABLE_NAME
where 1=2
No, but it is possible to return a query with no rows. In order to do this without referencing any tables, you can use a subquery:
SELECT NULL FROM (SELECT NULL) AS temp WHERE false;
This query will have one (empty) column, but no rows.
I've used the above construct when there is a query that is different in different cases, followed by a code loop that iterates through the results, and under some conditions you want to make it skip the loop. Replacing the query with the one above is a way of returning empty results and thus skipping the loop without an if block. Because the query contains no table names, that aspect of the code never needs to be changed, and for this reason I prefer it to adding a condition like WHERE false in an existing query.
I prefer this solution to the more concise one referencing dual because that construct is not supported in PostgreSQL; this solution works with any backend that supports subqueries.

MySQL Select from 1 Table, Insert into Another using Where across different databases

I have a select shown below that brings back the correct count per "sender_userid".
I want to insert this into a table in another database where there is a matching column "userid".
I'm not sure how to get the WHERE clause to work when used across database.
I've tried database.table.column but this appears wrong.
Is this possible? thx
WHERE statements must come before ORDER BY and GROUP BY statements. Also you should use the ON operator. Try this:
INSERT INTO dating_users.statistics (messages_sent)
SELECT COUNT(pid) FROM dating_messages.messages M
JOIN dating_users.statistics S
ON (S.userid = M.sender_userid)
GROUP BY sender_userid ORDER BY sender_userid ASC;
Edit: sorry I didn't realize that you were missing your actual JOIN statement. Just because you are INSERTing into a table doesn't make any data accessible from that table. You still need to JOIN to it.

MySQL IN() clause multiple returns

I have a special data environment where I need to be returned data in a certain way to populate a table.
This is my current query:
SELECT
bs_id,
IF(bs_board = 0, 'All Boards', (SELECT b_name FROM certboards WHERE b_id IN (REPLACE(bs_board, ';', ',')))) AS board
FROM boardsubs
As you can see I have an if statement then a special subselect.
The reason I have this is that the field bs_board is a varchar field containing multiple row IDs like so:
1;2;6;17
So, the query like it is works fine, but it only returns the first matched b_name. I need it to return all matches. For instance in this was 1;2 it should return two boards Board 1 and Board 2 in the same column. Later I can deal with adding a <br> in between each result.
But the problem I am dealing with is that it has to come back in a single column both name, or all names since the field can contain as many as the original editor selected.
This will not work the way you're thinking it will work.
Let's say bs_board is '1;2;3'
In your query, REPLACE(bs_board, ';', ',') will resolve to '1,2,3', which is a single literal string. This makes your final subquery:
SELECT b_name FROM certboards WHERE b_id IN ('1,2,3')
which is equivalent to:
SELECT b_name FROM certboards WHERE b_id = '1,2,3'
The most correct solution to the problem is to normalize your database. Your current system or storing multiple values in a single field is exactly what you should never do with an RDBMS, and this is exactly why. The database is not designed to handle this kind of field. You should have a separate table with one row for each bs_board, and then JOIN the tables.
There are no good solutions to this problem. It's a fundamental schema design flaw. The easiest way around it is to fix it with application logic. First you run:
SELECT bs_id, bs_board FROM boardsubs
From there you parse the bs_board field in your application logic and build the actual query you want to run:
SELECT bs_id,
IF(bs_board = 0, 'All Boards', (SELECT b_name FROM certboards WHERE b_id IN (<InsertedStringHere>) AS board
FROM boardsubs
There are other ways around the problem, but you will have problems with sorting order, matching, and numerous other problems. The best solution is to add a table and move this multi-valued field to that table.
The b_id IN (REPLACE(bs_board, ';', ',')) will result in b_id IN ('1,2,6,7') which is different from b_id IN (1,2,6,7) which is what you are looking for.
To make it work either parse the string before doing the query, or use prepared statements.