mySQL/SQlite subtractive query - mysql

I need a query in which it starts off by selecting the entire table, then there would be a few more querys that would remove entries from the first query. Ive accomplished this by using several querys and then comparing the results in my application. I was wondering if I can accomplish this in a single query.
Algorithm
Select All AccountIDs from table
Select AccountIDs from table where parameter1 = true
Remove those matches from the original query result
Select AccountIDs from table where parameter2 = true
Remove those matches from the remaining query result
and so on up to N parameters.
This would need to also be compatible with both mySQL and SQLite

I think you are looking for this:
SELECT AccountID FROM the_table
LEFT JOIN (
SELECT AccountID FROM the_table
WHERE
parameter1 = true OR
... OR
parameterN = true ;
) AS not_included USING (AccountID)
WHERE not_included.AccountID IS NULL -- only items with no match in the "not_included" sub-query
The not_included subquery returns all items for which any parameter is set to TRUE. You actually want to exclude these records from your final result set.
Then LEFT-JOIN the_table (i.e. all items) to this sub-result. The WHERE...IS NULL clause excludes items present in the_table but not present in not_included.
Therefore only items which you do not want to exclude remain in the final result set.

The most direct way to implement your algorithm is to use a compound SELECT statement:
SELECT AccountID FROM MyTable
EXCEPT
SELECT AccountID FROM MyTable WHERE parameter1 = 1
EXCEPT
SELECT AccountID FROM MyTable WHERE parameter2 = 1
However, this is also possible with a single WHERE expression:
SELECT AccountID
FROM MyTable
WHERE NOT (parameter1 = 1 OR
parameter2 = 1 OR
...)

Related

Mysql: Is it possible to use a subquery inside a from clause in order to pick the table name from another table

I was wondering if there's any way to add a subquery with a switch case to the form clause of my select query in order to select a table based on a condition.
For example:
select a.*
from (select (case when (table2.column = 'something')
then (table2.tablename1)
else (table2.tablename2)) as tablename
from table2
where table2.column2 = 'blabla'
limit 1
) a
I tried to write that in many variation & so far non of them worked.
On the most successful tryouts (when I got no mysql errors) it returned the name of the table as the result itself (for example: the value that's in table2.tablename2). I understand why it did that (because I selected everything from a select results...) but how can I use the tablename from the results in order to set the table on the main query?
Hope that make sense...
Any idea?

Select record using values from a previous COUNT() IN MYSQL

I obtain a series of values that appear only one time in my database using COUNT in mysql that list below:
valueName
---------
value1
value2
value3
value4
I need a script that retrieves all records in a table where valueName are not the values listed in the initial count, and I need this two steps to run in a single script (doesn't matter how many parts it has).
I've got the script to obtain the list above like this:
SELECT field AS new_name FROM table GROUP BY field HAVING COUNT(field) = 1;
And it works.
The problem is that I don't know how to work with the aggregated result of the first step. Maybe using some kind of function. Or loop (I don't think in SQL..).
I've tried different things like attaching a COUNT inside a WHERE clause and others but it doesn't work.
Please help!
Use a join:
select t.*
from table t join
(SELECT field
FROM table
GROUP BY field
HAVING COUNT(field) > 1
) filter
on t.field = filter.field;
If you have a primary key in your table and an index on table(field, pk), the following is probably faster:
select t.*
from table t
where exists (select 1
from table t2
where t2.field = t.field and t2.pk <> t.pk
);
Try this:
SELECT table.* FROM table
JOIN
(SELECT field FROM table GROUP BY field HAVING COUNT(field) > 1) newtable
ON
table.field = newtable.field;
This should work.

How to return NULL when result is empty?

I have a simple query that selects one field and only one row, thus one value.
Is there any way to make it return NULL if the query results in an empty set? Instead of returning zero rows?
I think I need to use something with NOT EXISTS, THEN NULL but not certain about it.
select
(Your entire current Select statement goes here) as Alias
from
dual
dual is a built in table with a single row that can be used for purposes like this. In Oracle this is mandatory. MySQL supports it, but you can also just select a single value without specifying a table, like so:
select
(Your entire current Select statement goes here) as Alias
In either case you're selecting a single value. This means that:
If your select returns one value, that value is returned.
If your select statement returns one column, but no rows, NULL will be returned.
If your select statement returns multiple columns and/or multiple rows, this won't work and the query fails.
An easy way to do this is with aggregation:
select max(col)
from t
where <your condition here>
This always returns one row. If there is no match, it returns NULL.
Late reply but I think this is the easiest method:
SELECT
IFNULL((SELECT your query), NULL)
Use a UNION with a NOT EXISTS(original where clause)
select col1
from mytable
where <some condition>
union
select null
where not exists (
select * from mytable
where <some condition>)
You can use COALESCE for example:
SELECT COALESCE(Field1,NULL) AS Field1 FROM Table1
Edit 1:
sorry i mistake with return field as null not result set,for result set return as null use Union and Exist Function like this:
SELECT NULL AS Field1 FROM Table1 WHERE not EXISTS(SELECT Field1 FROM Table1 WHERE Field2>0)
UNION
SELECT Field1 FROM Table1 WHERE Field2>0

Returning a value even if no result

I have this kind of simple query that returns a not null integer field for a given id:
SELECT field1 FROM table WHERE id = 123 LIMIT 1;
The thing is if the id is not found, the resultset is empty. I need the query to always return a value, even if there is no result.
I have this thing working but I don't like it because it runs 2 times the same subquery:
SELECT IF(EXISTS(SELECT 1 FROM table WHERE id = 123) = 1, (SELECT field1 FROM table WHERE id = 123 LIMIT 1), 0);
It returns either field1 if the row exists, otherwise 0. Any way to improve that?
Thanks!
Edit following some comments and answers: yes it has to be in a single query statement and I can not use the count trick because I need to return only 1 value (FYI I run the query with the Java/Spring method SimpleJdbcTemplate.queryForLong()).
MySQL has a function to return a value if the result is null. You can use it on a whole query:
SELECT IFNULL( (SELECT field1 FROM table WHERE id = 123 LIMIT 1) ,'not found');
As you are looking for 1 record, (LIMIT 1) then this will work.
(SELECT field1 FROM table WHERE id = 123)
UNION
(SELECT 'default_value_if_no_record')
LIMIT 1;
Can be a handy way to display default values, or indicate no results found. I use it for reports.
See also http://blogs.uoregon.edu/developments/2011/03/31/add-a-header-row-to-mysql-query-results/ for a way to use this to create headers in reports.
You could include count(id). That will always return.
select count(field1), field1 from table where id = 123 limit 1;
http://sqlfiddle.com/#!2/64c76/4
You can use COALESCE
SELECT COALESCE(SUM(column),0)
FROM table
If someone is looking to use this to insert the result INTO a variable and then using it in a Stored Procedure; you can do it like this:
DECLARE date_created INT DEFAULT 1;
SELECT IFNULL((SELECT date FROM monthly_comission WHERE date = date_new_month LIMIT 1), 0)
INTO date_created
WHERE IFNULL((SELECT date FROM monthly_comission WHERE date = date_new_month LIMIT 1), 0) = 0;
With this you're storing in the variable 'date_created' 1 or 0 (if returned nothing).
Do search with LEFT OUTER JOIN. I don't know if MySQL allows inline VALUES in join clauses but you can have predefined table for this purposes.
k-a-f's answer works for selecting one column, if selecting multiple column, we can.
DECLARE a BIGINT DEFAULT 1;
DECLARE b BIGINT DEFAULT "name";
SELECT id, name from table into a,b;
Then we just need to check a,b for values.
if you want both always a return value but never a null value you can combine count with coalesce :
select count(field1), coalesce(field1,'any_other_default_value') from table;
that because count, will force mysql to always return a value (0 if there is no values to count) and coalesce will force mysql to always put a value that is not null

MySQL request from two tables interacting with each other

Tables i have
Table1 user_id, date
Table2 user_id, status
I need something like
UPDATE Table2
SET status = 2
WHERE user_id in ( {SELECT user_id FROM Table1 WHERE date > 0} )
In other words i need to see if date in table1 is more than 0000-00-00 then grab user_id of people who match this criteria and use them in table2 to set their status to 2.
Problem is that i need to do it for more than one user so request inside request does not work for me, it only works when there's one row in result.
I think what you've written should work, but what's with the curly braces? Just remove them to make it like this:
UPDATE Table2
SET status = 2
WHERE user_id in (SELECT user_id FROM Table1 WHERE date > 0)
According to the MySQL documentation, IN should work with a subquery.
The ANY keyword, which must follow a comparison operator, means “return TRUE if the comparison is TRUE for ANY of the values in the column that the subquery returns.”
When used with a subquery, the word IN is an alias for = ANY.
Are you using PHP or some other language to make SQL calls? If so, it might easier to just,
firstly: select user ids from table 1
secondly: loop through each row
thirdly: execute the update
Regards,
Mark