union for returning default output - mysql

I have a query which may not return anything if there is no match (if uuid and scene_id do not match).
My query:
select active from likes where uuid=12 and scene_id=22
so inorder to solve the problem and return 0 in this situation; I am union it with a default value and add 'limit 1' like the following query; but I could not get it work!
select * from ((select active from likes
where uuid=12 and scene_id=22)as a
union all
(select 0 as 'active')as b)limit 1;
it gives me a syntax error on "as b "
What am I doing wrong in this case?
Please let me know if you need more clarification.

Change your query as below (remove the inner table alias)
select *
from
(
select active from likes where uuid=12 and scene_id=22
union all
select BIN(0) as 'active'
) tab limit 1;
Problem was that, active is of bit type and in second select 0 is INT type. Just convert 0 to binary representation using BIN() function.

I think you overdid the parentheses. This should work:
select
active
from
(select active, 0 as importance from likes
where uuid=12 and scene_id=22
union all
select FALSE, 1) x
order by importance
limit 1
Note the extra importance column. It makes sure that the actual value from Active is used. Otherwise, the actual row and the default may theoretically be returned in any order.
But I actually agree with Joe Stefanelli's comment, that your application should handle this rather than your query.
Example: http://sqlfiddle.com/#!2/7cfbe3/1

Related

DENSE_RANK() OVER and IFNULL()

Let's say I have a table like this -
id
number
1
1
2
1
3
1
I want to return the second largest number, and if there isn't, return NULL instead. In this case, since all the numbers in the table are the same, there isn't the second largest number, so it should return NULL.
These codes work -
SELECT IFNULL((
SELECT number
FROM (SELECT *, DENSE_RANK() OVER(ORDER BY number DESC) AS ranking
FROM test) r
WHERE ranking = 2), NULL) AS SecondHighestNumber;
However, after I changed the order of the query, it doesn't work anymore -
SELECT IFNULL(number, NULL) AS SecondHighestNumber
FROM (SELECT *, DENSE_RANK() OVER(ORDER BY number DESC) AS ranking
FROM test) r
WHERE ranking = 2;
It returns blank instead of NULL. Why?
Explanation
This is something of a byproduct of the way you are using subquery in your SELECT clause, and really without a FROM clause.
It is easy to see with a very simple example. We create an empty table. Then we select from it where id = 1 (no results as expected).
CREATE TABLE #foo (id int)
SELECT * FROM #foo WHERE id = 1; -- Empty results
But now if we take a left turn and turn that into a subquery in the select statement - we get a result!
CREATE TABLE #foo (id int)
SELECT (SELECT * FROM #foo WHERE id = 1) AS wtf; -- one record in results with value NULL
I'm not sure what else we could ask our sql engine to do for us - perhaps cough up an error and say I can't do this? Maybe return no results? We are telling it to select an empty result set as a value in the SELECT clause, in a query that doesn't have any FROM clause (personally I would like SQL to cough up and error and say I can't do this ... but it's not my call).
I hope someone else can explain this better, more accurately or technically - or even just give a name to this behavior. But in a nutshell there it is.
tldr;
So your first query has SELECT clause with an IFNULL function in it that uses a subquery ... and otherwise is a SELECT without a FROM. So this is a little weird but does what you want, as shown above. On the other hand, your second query is "normal" sql that selects from a table, filters the results, and lets you know it found nothing -- which might not be what you want but I think actually makes more sense ;)
Footnote: my "sql" here is T-SQL, but I believe this simple example would work the same in MySQL. And for what it's worth, I believe Oracle (back when I learned it years ago) actually would cough up errors here and say you can't have a SELECT clause with no FROM.

Select value that only occurs once

I am trying to learn on how to select values that only occur once.
I would like to select the names of applicants who only have one and one only application.
SELECT name FROM (SELECT COUNT(anumber) AS count FROM APPLIES
GROUP BY anumber HAVING (count = 1)) AS x;
Could you please assist me as I cannot figure out where I am going wrong with this, I am still new to using MySQL.
SELCT name FROM APPLIES
GROUP BY anumber
HAVING COUNT(anumber)=1
This should get you the names that have exactly one anumber (I am assuming anumber means application number here)
Here's a link explaining different use cases of GROUP BY and HAVING which you can refer to if you want something else - https://www.w3resource.com/sql/aggregate-functions/count-having.php
I think this should be enough. The output is all the names in table applies, that occur only once.
SELECT name FROM APPLIES
GROUP BY anumber
having count(anumber) = 1;
EDIT:
Looking at your query, you are trying to select a name from this subquery, that only has a "count":
SELECT COUNT(anumber) AS count FROM APPLIES
GROUP BY anumber HAVING (count = 1)

Use the result of the MySQL SELECT query as a WHERE condition in the same query

I'm trying to do this query:
SELECT MAX(`peg_num`)
AS "indicator"
FROM `list`
WHERE `list_id` = 1
AND "indicator" >= 1
But I'm getting the result of NULL. What I should be getting is 99, as the range of peg_num is 00 to 99.
The value checked against "indicator" should actually be a user input, so I want it to be versatile. But, it does give me the correct result if I flip the equality around:
SELECT MAX(`peg_num`)
AS "indicator"
FROM `list`
WHERE `list_id` = 1
AND "indicator" <= 1
Why would it do this?
Edit:
As suggested, I'm using the HAVING clause... but I just ditched the alias for now anyway:
SELECT MAX(`peg_num`) AS "indicator"
FROM `list`
GROUP BY `list_id`
HAVING MAX(`peg_num`) <= 40
Still very stubborn. It gives me 99 now no matter the value in the having clause, regardless of the inequality.
Edit2:
As a clarification:
What I want to happen is the query select the largest value in the range of peg_num, but only if it is larger than a user-given input. So, the max in this case is 99. If the user wants to select a number like 101, he/she can't because it's not in the range.
Because of double quotes, "indicator" in WHERE clause is interpreted as a string. Thus, it evaluates to 0, meaning it is always less than 1. Column names must be escaped in backticks.
Keep in mind that WHERE clause is executed before SELECT an hence aliases defined in SELECT can not be used in WHERE clause.
SELECT MAX(`peg_num`) AS `indicator`
FROM `list`
WHERE `list_id` = 1
HAVING `indicator` >= 1
You might want to check out the link on the answer to another Stack question about not being allowed to use alias in where clause:
Can you use an alias in the WHERE clause in mysql?
Paul Dixon cites:
It is not allowable to refer to a column alias in a WHERE clause,
because the column value might not yet be determined when the WHERE
clause is executed. See Section B.1.5.4, “Problems with Column
Aliases”.
Also:
Standard SQL disallows references to column aliases in a WHERE clause.
The behavior you're seeing in your query when you swap the '<=' and '>=' operators, results from the query comparing the string/varchar 'indicator' to the number 1.
That's why you see the correct answer..when ('indicator' >= 1) which is true, and null when ('indicator' <= 1) which is false.
I don't know, but I'm amazed either of them work at all. WHERE works serially on fields belonging to individual records and I wouldn't expect it to work on "indicator" since that's a group calculation.
Does this do what you want?
SELECT max(`peg_num` ) AS "indicator"
FROM actions
WHERE `peg_num` >=1
AND `list_id` <= 1
WHERE happens before SELECT, and don't know what's "indicator".
You should use HAVING (with GROUP BY) to use the SELECT fields
Here's the documentation for syntax
http://dev.mysql.com/doc/refman/5.5/en/select.html
Something like this is the idea
SELECT MAX(peg_num) AS indicator
FROM list
WHERE list_id = 1
HAVING indicator <= 1
I can't test it and i never met Mysql so just the idea,
You should use HAVING
No quotes in HAVING condition
This must work:
SELECT MAX(peg_num)
AS indicator
FROM list
WHERE list_id = 1
HAVING indicator >= 1
I completely re-invented my query and it worked. The thing is, I had to use a nested query (and I wanted to not do that as much as possible, my professor had always discouraged it).
Anyway, here it is:
SELECT IF(`key` < 900, `key`, null) `key`
FROM (
(
SELECT MAX( `peg_num` ) AS `key`
FROM `list`
WHERE `list_id` =1
) AS `derivedTable`
)

Table statistics (aka row count) over time

i'm preparing a presentation about one of our apps and was asking myself the following question: "based on the data stored in our database, how much growth have happend over the last couple of years?"
so i'd like to basically show in one output/graph, how much data we're storing since beginning of the project.
my current query looks like this:
SELECT DATE_FORMAT(created,'%y-%m') AS label, COUNT(id) FROM table GROUP BY label ORDER BY label;
the example output would be:
11-03: 5
11-04: 200
11-05: 300
unfortunately, this query is missing the accumulation. i would like to receive the following result:
11-03: 5
11-04: 205 (200 + 5)
11-05: 505 (200 + 5 + 300)
is there any way to solve this problem in mysql without the need of having to call the query in a php-loop?
Yes, there's a way to do that. One approach uses MySQL user-defined variables (and behavior that is not guaranteed)
SELECT s.label
, s.cnt
, #tot := #tot + s.cnt AS running_subtotal
FROM ( SELECT DATE_FORMAT(t.created,'%y-%m') AS `label`
, COUNT(t.id) AS cnt
FROM articles t
GROUP BY `label`
ORDER BY `label`
) s
CROSS
JOIN ( SELECT #tot := 0 ) i
Let's unpack that a bit.
The inline view aliased as s returns the same resultset as your original query.
The inline view aliased as i returns a single row. We don't really care what it returns (except that we need it to return exactly one row because of the JOIN operation); what we care about is the side effect, a value of zero gets assigned to the #tot user variable.
Since MySQL materializes the inline view as a derived table, before the outer query runs, that variable gets initialized before the outer query runs.
For each row processed by the outer query, the value of cnt is added to #tot.
The return of s.cnt in the SELECT list is entirely optional, it's just there as a demonstration.
N.B. The MySQL reference manual specifically states that this behavior of user-defined variables is not guaranteed.

Is there a special character in mySql that would return always true in WHERE clauses?

Is there a character, say, $,
SELECT * FROM Persons WHERE firstName='Peter' AND areaCode=$;
such that the statement would return the same as
SELECT * FROM Persons WHERE firstName='Peter'
i.e. areaCode=$ would always return always true and, thus, effectively “turns of” the criteria areaCode=...
I’m writing a VBA code in Excel that fetches some rows based on a number of criteria. The criteria can either be enabled or disabled. A character like $ would make the disabling so much easier.
instead of disabling it, pass it through to your query as NULL and use COALESCE:
SELECT *
FROM Persons
WHERE firstName='Peter'
AND areaCode = COALESCE(<your parameter>, areaCode);
%
See Wildcards
You could use NULL for this purpose:
AND (areaCode = ? OR ? IS NULL)
I think you could use something like
SELECT * FROM Persons WHERE firstName=firstName
of course without quotes
From your question I assume that you actually want the ability to include or exclude the where clause, in which case you need to use or.
SELECT *
FROM Persons
WHERE ( 1 = 2
OR ( firstName = 'Peter'
AND < more conditions if needed >
)
)
In this example 1 <> 2 so the only condition evaluated is firstName = 'Peter'. If you then want to ignore the where clause you change 2 to 1. As 1 = 1 this is evaluated for every row and the rest of the conditions will be ignored.