Avoid ambiguous condition in MySQL - mysql

I'm working on a very limited MySQL environment (all MySQL calls are passed as array parameters). The problem is I don't know how to resolve an ambiguos condition.
In this environment all MySQL calls take this form:
SELECT value1,value2,...,valueN
FROM table1,table2,...,tableN
WHERE cond1 OP cond2 OP ... OP condN
That's not a problem until you have the same column names in table1 and table2. Imagine table1 has columns {a,b,z} and table2 has column names {c,d,f,z}. I can do this:
SELECT *
FROM table1, table2
WHERE a='3' AND table1.z='5'
Perfect but, one of the limitations is that I can't use table1.z format, just z='5' that produces a collision.
So, the question is: is there any way to prevent this ambiguosity without the use of table name prefix in the condition part? (for example, it will be great if there is a way to use only part of table2 or say that table1 has priority in case of ambiguity).

There is no way to avoid a collision if you can't qualify which table "myColumn" comes from.
Your constraints seem kind of silly... You're basically asking for valid result when you assert that you cannot write valid SQL....
Perhaps instead of SELECTing from table1, you would SELECT from a nested subquery in which you aliased the column names...
For example:
if table1 and table2 both have column "myColumn"
Rather than:
SELECT
*
FROM
table1,table2
WHERE myColumn = #value -- produces collision!
Could you say:
SELECT
*
FROM
(SELECT myColumn AS foo FROM table1) newTable1,
(SELECT myColumn AS bar FROM table2) newTable2
WHERE
foo = #value
This way you're not fully qualifying the tables in the outer WHERE clause but you are re-aliasing the columns inside the subqueries (thus making them into different names for the outer query)
This seems like a roundabout exercise though
EDIT:
http://thedailywtf.com/Articles/SQL-Sentences.aspx
"MySQL sentences?"

Related

Split the values from ('1,2,3') to ('1','2','3') or (1,2,3) in sql

I have a table field named category_ids (text) which saves another table's ids as "1,2,3".
Now i want to use this category_ids to a sql IN() query. the query will be like tab1.category_id IN (select category_ids from tab2). but i'm facing issue as select category_ids from tab2 returns '1,2,3' so IN() query not working.
Is there any simple way to convert '1,2,3' to ('1','2','3') or (1,2,3) in sql?
You may use FIND_IN_SET here:
SELECT *
FROM tab1
WHERE FIND_IN_SET(tab1.category_id,
(select category_ids from tab2));
This is just a sample query, your actual one may differ. But the point is that if you want to search for '1' inside a CSV string '1,2,3', then there is a way to do it.
As others have already mentioned, you should avoid storing CSV data in your tables. When I see FIND_IN_SET being heavily used there is usually a smell.
try
tab1.category_id IN (select REPLACE(category_ids, '''', '') from tab2)
If table2 has more than one row, you can use exists with find_in_set():
select t1.*
from table1 t1
where exists (select 1
from table2 t2
where find_in_set(t1.category_id, t2.category_ids) > 0
);
Note that this is a very poor data structure. You should have a single row for each category id in table2. If you did, then the query would be simpler and have better performance.

MySQL IF on Where clause

Is it possible to make a query that changes the where clause acording to some condition? For instance I want to select * from table1 where data is 19/July/2016 but if field id is null then do nothing, else compare id to something else. Like the query bellow?
Select * from table1 where date="2016-07-19" if(isnull(id),"",and id=(select * from ...))
Yes. This should be possible.
If we assume that date and id are references to columns in (the unfortunately named) table table1, if I'm understanding what you are attempting to achieve, we could write a query like this:
SELECT t.id
, t.date
, t....
FROM table1 t
WHERE t.date='2016-07-19'
AND ( t.id IS NULL
OR t.id IN ( SELECT expr FROM ... )
)
It would also be possible to incorporate the MySQL IF() and IFNULL() functions, if there's some requirement to do that.
As far as dynamically changing the text of the SQL statement after the statement is submitted to the database, no, that's not possible. Any dynamic changes to the SQL text would need to be done when the SQL statement is generated, before it is submitted to the database.
My personal preference would be to use a join operation rather than a IN (subquery) predicate.
I think you're trying too hard. If id is NULL that's equivalent to having a FALSE in the where clause. So:
Select * from table1 where date="2016-07-19" and id=(select * from ...)
Should only match the records you want. If id is NULL you get nothing.

MySQL select all from list where value not in table

I cannot create a virtual table for this. Basically what I have, is a list of values:
'Succinylcholine','Thiamine','Trandate','Tridol Drip'
I want to know which of those values is not present in table1 and display them. Is this possible? I have tried using left joins and creating a variable with the list which I can compare to the table, but it returns the wrong results.
This is one of the things I have tried:
SET #list="'Amiodarone','Ammonia Inhalents','Aspirin';
SELECT #list FROM table1 where #list not in (
SELECT Description
FROM table1
);
With only narrow exceptions, you need to have data in table form to be able to obtain those data in your result set. This is the essential problem that all attempts at a solution to this problem run into, given that you cannot create a temporary table. If indeed you can provide the input in any form or format (per your comment), then you can provide it in the form of a subquery:
(
SELECT 'Amiodarone' AS description
UNION ALL
SELECT 'Ammonia Inhalents'
UNION ALL
SELECT 'Aspirin'
)
(Note that that exercises the biggest of the exceptions I noted: you can select scalars directly, without a base table. If you like, you can express that explicitly -- in MySQL and Oracle, at least -- by selecting FROM DUAL.)
In that case, this should work for you:
SELECT
a.description
FROM
(
SELECT 'Amiodarone' AS description
UNION ALL
SELECT 'Ammonia Inhalents'
UNION ALL
SELECT 'Aspirin'
) a
LEFT JOIN table1
ON a.description = table1.description
WHERE table1.description IS NULL
That won't work. the variable's contents will be treated as a monolithic string - one solid block of letters, not 3 separate comma-separated values. The query will be parsed/executed as:
SELECT ... WHERE "'Amio.....rin'" IN (x,y,z,...)
^--------------^--- string
Plus, since you're just doing a sub-select on the very same table, there's no point in this kind of a construct. You could try mysql find_in_set() function:
SELECT #list
FROM table1
WHERE FIND_IN_SET(Description, #list) <> ''

Split the field value in a mysql JOIN query

I've got a column "code" which may have a string of multiple values e.g. "CODE1&CODE2"... I just need the first one for my JOIN ... kind of like code.split("&")[0]
SELECT myTable.*, otherTable.id AS theID
FROM myTable INNER JOIN otherTable
ON myTable.(+++ code before the & +++) = otherTable.code
The value in myTable may also just be CODE1
SUBSTRING_INDEX will do exactly what you want - return the substring of your column up to the specified character:
SELECT
myTable.*,
otherTable.id AS theID
FROM myTable
INNER JOIN otherTable
ON SUBSTRING_INDEX(myTable.code, '&', 1) = otherTable.code
More info at: http://dev.mysql.com/doc/refman/5.0/en/string-functions.html
And here's a fiddle demoing it: http://sqlfiddle.com/#!2/96a6e/2
Please note that this will be SLOW if you're joining many columns. You're not only eliminating the possibility of using an index, but performing a very slow string operation on every comparison. I wouldn't suggest using this on very large tables. If your data set is huge, you may want to consider rearchitecting your DB.

Defining aliases in a statistical query

I need to do:
SELECT COUNT(*)
FROM some_table
WHERE someAlias1 = someValue1
AND someAlias2 = someValue2;
someAlias is an alias for a column in some_table. In my case I can't name the columns directly; I need to use aliases.
The issue is that I only know about defining aliases inside the select clause which I don't see how I can do in this case.
Is there a way to accomplish what I need in this case?
edit: Why do I need aliases? I'm building a query from alternative parts, and the condition above applies to different columns from different tables, but with the same logical role. So I need a way to relate to different alternative columns with the same name.
I will appreciate if you answer this question only if you know an answer, even if you don't understand why may I need an alias
You could do a nested SELECT statement then draw the count out from the inner query, I don't really see a way to escape using the column names
SELECT COUNT(*)
FROM(
SELECT col1 as someAlias1,
col2 as someAlias2
FROM some_table
WHERE someAlias1 = someValue1
AND someAlias2 = someValue2
) as inner
I can't figure out a scenario where you can't name the columns directly. If the column name is duplicated, prepend the table name:
WHERE someTable1.someColumn1 = someValue1
If the column name is a reserved keyword or contains spaces, quote it:
WHERE `some Column1` = someValue1
You can even combine both:
WHERE someTable1.`some Column1` = someValue1
Why do you need to use aliases? The only reason to use aliases in your query would be for re-use in e.g. an "having" clause, like:
select count(*) as C
from some_table
where someAlias1=someValue1
and someAlias2=someValue2
having C > someLimit1;