SQL Query handle multiple WHERE - mysql

I intend to generate report through web interface.
My page content two field:
----------------------
Gender: Male Female (radio button)
Age: 10 to 20 (Select list)
------------------
How can I write query, they handle both situation, if user provide only "Gender" base WHERE clause or required gender or Age base WHERE clause.
I am want to write single query handle both situation.
Please help me
Regards,

Use and:
select *
from yourTable
where gender = 'Male'
and age between 10 and 20
If it is unsure whether a user enters a value, try or and a null check. You can do the same for gender:
select *
from yourTable
where gender = 'Male'
and (age is null or age between 10 and 20)

Your base query should be something like
SELECT *
FROM Customer
WHERE 1=1
And you should add clauses (" AND gender = something", " AND age between something and something") based on the parameters provided by user.
If the user does not select any parameters, the base query should work fine. If the user provides a parameter or both, the query becomes something like:
SELECT *
FROM Customer
WHERE 1=1
AND gender = "male"

Related

Grafana - How to create sql query part variable/macro for Mysql datasource

I have following query in Grafana which is backed by MySql DataSource.
SELECT
$__timeGroupAlias(ts,$__interval),
sum(total) AS "total"
FROM hp
WHERE
$__timeFilter(ts)
AND customer_type IN ($CustomerType) AND age IN ($age) AND gender IN ($gender)
GROUP BY 1
ORDER BY $__timeGroup(ts,$__interval)
There are multiple singleStat/panel/graphs in the Dashboard which use different select parameters but the WHERE condition remains same in all of them.
I want to keep the condition as separate constant variable so that I can add just that variable in every query.
I tried to build my query like this.
SELECT
$__timeGroupAlias(ts,$__interval),
sum(total) AS "total"
FROM hp
$where_condition
GROUP BY 1
ORDER BY $__timeGroup(ts,$__interval)
and declared where_condition as WHERE $__timeFilter(ts) AND customer_type IN ($CustomerType) AND age IN ($age) AND gender IN ($gender).
But the query fails, because the internal variables ($CustomerType,$age,$gender) are not resolved by query generator and generated query looks like this.
SELECT
UNIX_TIMESTAMP(ts) DIV 900 * 900 AS "time",
sum(total) AS "total"
FROM hp
ts BETWEEN FROM_UNIXTIME(1548311714) AND FROM_UNIXTIME(1548398114)
AND customer_type IN ($CustomerType) AND age IN ($age) AND gender IN ($gender)
GROUP BY 1
ORDER BY UNIX_TIMESTAMP(ts) DIV 900 * 900
Is there a way to resolve the variables which are contained in other variables. Or Is there any other way to externalise part of query which contains variables?
constant variable type generates only static string. It didn't substitute any variables. Switch to query type and use MySQL to return string, which will have exact string value for your where_condition variable. Query:
SELECT 'WHERE $__timeFilter(ts) AND customer_type IN ($CustomerType) AND age IN ($age) AND gender IN ($gender)'
IMHO: variable substitution should works also for constant type. You can open feature request for that https://github.com/grafana/grafana/issues.
I also had issues with quotes, here is my solution that supports 'All' and many selected:
SELECT '
task_run_table.is_system = false
AND
(
''__all__'' = ''${user:raw}''
OR
task_run_table.user = any ( string_to_array(''${user:raw}'', '','')::text[])
)
AND
(
''__all__'' = ''${job:raw}''
OR
task_run_table.job_name = any ( string_to_array(''${job:raw}'', '','')::text[])
)
'
All value was overridden to __all__.
It's used like this:
SELECT
$__timeGroup(task_run_table.start_time, '$interval', NULL),
task_run_table.name AS metric,
COUNT(*) AS value
FROM
task_run_table
WHERE
$__timeFilter(task_run_table.start_time)
AND
${default_filter:raw}
AND
task_run_table.state = $state
GROUP BY time, task_run_table.name
ORDER BY time, value DESC

Passing values to a query that may be null

I'm trying to make a filter section for a website that will return objects from the DB.
SELECT *
FROM users
WHERE type = "1"
AND age < 50
AND age > 20
When entering this query, some users may not want to set a type, just filter it by age? Is there any sort of wild card i can pass into the query so it returns all if it not been defined by the user?
The type can either be 1, 2 or 3. if this is not passed into it, i want it to return all users between the age of 20 and 50, and then all types?
These could be two possible solutions, first is simple if you want all records when age between 50 and 20. Second query will return records if type=1 and age between 50 and 20,
SELECT *
FROM users
WHERE age BETWEEN 20 AND 50
OR
SELECT * FROM users
WHERE
IF(type == 1)
THEN
type = 1
ELSE
1=1
END IF
AND age BETWEEN 20 AND 50
SELECT * FROM USERS WHERE AGE BETWEEN 20 AND 50 AND COALESCE(TYPE,'1')=1
Try this query :
select * from table_name where age between 20 and 50 AND type is null

MySQL Select when case

i have those tables and i want to check the same attribute at the same time:
Person
id---name
1----Paul
2----Tom
3----Jim
Age
id---wert------personId
1----28--------1
2----25--------1
3----30--------3
i want to do something like this.
select * from Person p, Age where personId = p.id and CASE WHEN
name = 'Paul' THEN Age > 28 WHEN name = 'Tom' THEN Age <....
How it is possible? With a CASE THEN in the WHERE clause? Please don't think about the structure of the table but only about the principle.
Any Ideas?
Thank
What you're trying to do is possible like so
select
*
from
Person p, Age
where personId = p.id
and CASE
WHEN name = 'Paul' THEN Age > 28
WHEN name = 'Tom' THEN Age <....
WHEN expr then expr that evals to bool
END
CASE WHEN THEN I believe need to be part of an expression, not an expression themselves. It's common use case is in the select, however you can use it in the where.
In a select this would be:
select
case name
when 'paul' then 28
when 'jim' then 30
end
from X
To use it within an where you would do this:
select * from X where age = case name when 'jim' then 28 else 30 end
Depending on what you are attempting to achieve, you may want to consider OR statements instead of case in your where clause.

Append blank results to end in alphabetical order

I would like to return a list of items by alphabetical order, but have the "empty" results append to the end as opposed to appearing at the beginning. Is there a way to do this using the MySQL ORDER statement, or perhaps another way?
SELECT * FROM persons WHERE status = 'active' ORDER BY lastName;
What I get:
Jason
Peter
Frank Asimov
Reda Banks
Scott Sorrel
What I want:
Frank Asimov
Reda Banks
Scott Sorrel
Jason
Peter
SELECT * FROM persons WHERE status = 'active'
ORDER BY case when ifnull(lastName,'') = '' then 1 else 0 end, lastname
You can do it using the FIELD statement. It goes something like that:
SELECT [...] ORDER BY FIELD(lastName, '') DESC
This will either append all the empty-string lastnames to the end. If instead of empty strings, you have NULL on your database:
SELECT [...] ORDER BY FIELD(lastName, NULL) DESC;
I believe all you need is to ORDER BY the firstName:
SELECT * FROM persons WHERE status = 'active' ORDER BY lastName, firstName

Select multiple sums with MySQL query and display them in separate columns

Let's say I have a hypothetical table like so that records when some player in some game scores a point:
name points
------------
bob 10
mike 03
mike 04
bob 06
How would I get the sum of each player's scores and display them side by side in one query?
Total Points Table
bob mike
16 07
My (pseudo)-query is:
SELECT sum(points) as "Bob" WHERE name="bob",
sum(points) as "Mike" WHERE name="mike"
FROM score_table
You can pivot your data 'manually':
SELECT SUM(CASE WHEN name='bob' THEN points END) as bob,
SUM(CASE WHEN name='mike' THEN points END) as mike
FROM score_table
but this will not work if the list of your players is dynamic.
In pure sql:
SELECT
sum( (name = 'bob') * points) as Bob,
sum( (name = 'mike') * points) as Mike,
-- etc
FROM score_table;
This neat solution works because of mysql's booleans evaluating as 1 for true and 0 for false, allowing you to multiply truth of a test with a numeric column. I've used it lots of times for "pivots" and I like the brevity.
Are the player names all known up front? If so, you can do:
SELECT SUM(CASE WHEN name = 'bob' THEN points ELSE 0 END) AS bob,
SUM(CASE WHEN name = 'mike' THEN points ELSE 0 END) AS mike,
... so on for each player ...
FROM score_table
If you don't, you still might be able to use the same method, but you'd probably have to build the query dynamically. Basically, you'd SELECT DISTINCT name ..., then use that result set to build each of the CASE statements, then execute the result SQL.
This is called pivoting the table:
SELECT SUM(IF(name = "Bob", points, 0)) AS points_bob,
SUM(IF(name = "Mike", points, 0)) AS points_mike
FROM score_table
SELECT sum(points), name
FROM `table`
GROUP BY name
Or for the pivot
SELECT sum(if(name = 'mike',points,0)),
sum(if(name = 'bob',points,0))
FROM `table
you can use pivot function also for the same thing .. even by performance vise it is better option to use pivot for pivoting... (i am talking about oracle database)..
you can use following query for this as well..
-- (if you have only these two column in you table then it will be good to see output else for other additional column you will get null values)
select * from game_scores
pivot (sum(points) for name in ('BOB' BOB, 'mike' MIKE));
in this query you will get data very fast and you have to add or remove player name only one place
:)
if you have more then these two column in your table then you can use following query
WITH pivot_data AS (
SELECT points,name
FROM game_scores
)
SELECT *
FROM pivot_data
pivot (sum(points) for name in ('BOB' BOB, 'mike' MIKE));