SQL : Conditional result used in the same conditional outputs - mysql

I wondering how to process a SQL comparision without redo the same query twice in the statement.
Here is what I am looking for :
SELECT columnName10,
IF( SELECT columnName20
FROM OtherExampleTable
WHERE id = 15 IS NULL, 'nothing', SELECT columnName20
FROM OtherExampleTable
WHERE id = 15
) AS AliasColumn
FROM ExampleTable
As you can see, the query SELECT columnName20 FROM OtherExampleTable WHERE id = 15 is made 2 times.
How could I do the same thing whithout the duplicate query ?
Thank you guys.

You could use COALESCE:
SELECT column10, COALESCE(
(SELECT columnName10
FROM OtherExampleTable WHERE id=15), 'nothing')
FROM ExampleTable;

Two solutions.
Using IFNULL()
SELECT columnName10,
IFNULL( SELECT columnName20
FROM OtherExampleTable
WHERE id = 15, 'nothing' ) AS AliasColumn
FROM ExampleTable
Use user variable
SELECT columnName10,
IF( #value IS NULL, 'nothing', #value:=(SELECT columnName20
FROM OtherExampleTable
WHERE id = 15)
) AS AliasColumn
FROM ExampleTable

Try This
SELECT columnName10,
IFNULL(SELECT columnName20
FROM OtherExampleTable
WHERE id = 15 LIMIT 1,'nothing') AS AliasColumn
FROM ExampleTable;
in this query also write LIMIT 1 if id is not primary key

Related

Select random value in SQL

Is there a way to do the following query? It would save me having to go out of SQL to do post-processing of the query:
SELECT date, RANDOM('CA', 'DE', 'AZ') FROM table LIMIT 3
And the result would be something like:
2014-01-01,"CA"
2014-01-02,"CA"
2014-01-03,"DE"
Is there a way to do the RANDOM operation in SQL?
Get your set of values to table/subquery with UNION ALL, sort by RAND() and return 1 value:
SqlFiddleDemo
SELECT id,
(SELECT 'CA' AS 'col'
UNION ALL
SELECT 'DE'
UNION ALL
SELECT'CZ'
ORDER BY RAND() LIMIT 1) AS Random
FROM tab
LIMIT 3
Or use:
SqlFiddleDemo_2
SELECT id,
ELT(FIELD(CEILING(RAND()*3), 1, 2, 3),'CA','CZ', 'DE') AS Rand
FROM tab
LIMIT 3
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX('CA,DE,AZ',',',CEILING(RAND()*3)),',',-1);
or something like that
One way is this if you want to select the random string
select any_column_name,ELT(FLOOR(RAND()*8)+1,'US', 'CA', 'FR', 'DE' , 'UK' , 'IR' ,
'RU' , 'GR') from table_name;
Let me know if that is what you want.

run a query if another query fetches null value in mysql

I want to fetch max no from invgatepass on the basis of time and date and if it returns null then I want to run another query on the basis of different conditions if that also fails to fetch any data then I want to fetch '1'.
This is something which I want.
But inside COALESCE function, second parameter is not allowed to be query.
Can some one solve this problem.
I don't want to use two separate queries after checking the condition inside php code.
SELECT COALESCE(
MAX(SUBSTRING_INDEX(InwardNo, '-', -1))+1,
SELECT COALESCE
(
MAX(SUBSTRING_INDEX(InwardNo, '-', -1))+1,
1
)
FROM
invgatepass
WHERE
DATE(CreationDateTime)=CURDATE()
AND
(EXTRACT(HOUR FROM CreationDateTime)) < '17'
)
AS CODE FROM
invgatepass
WHERE
DATE(CreationDateTime)=DATE_SUB(CURDATE(), INTERVAL 1 DAY)
AND
(EXTRACT(HOUR FROM CreationDateTime)) >= '17'"
A subquery is allowed inside the coalesce function, but the subquery must be enclosed within braces.
Look at this demo: http://www.sqlfiddle.com/#!2/fb3d8/2
This query compiles fine because all subqueries are enclosed within braces:
SELECT coalesce(
( SELECT null ),
( SELECT id FROM test WHERE id = 10 ),
( SELECT id FROM test WHERE id = 4 ),
( SELECT id FROM test WHERE id = 2 )
) result
;
This query throws a syntax error, because a second subquery has no braces around it:
SELECT coalesce(
( SELECT null ),
SELECT id FROM test WHERE id = 10,
( SELECT id FROM test WHERE id = 4 ),
( SELECT id FROM test WHERE id = 2 )
) result
;
Side note:
You do not need 2 Coalesce:
coalesce ( null, null, 1)
is about the same as
coalesce ( null, coalesce ( null, 1))

looking for tricky sql query solution

i'm having the following database structure (for messaging):
id from_userid to_userid time_stamp message
let's say i'm user with id 1 and i want to get a list of ALL user_ids i've been interacting with, sorted by timestamp - any idea how to do it?
thanks
Something like this, perhaps?
SELECT *
FROM (
SELECT from_id AS id, time_stamp
FROM <table>
WHERE to_id=<user id>
UNION
SELECT to_id AS id, time_stamp
FROM <table>
WHERE from_id=<user id>
) AS t
ORDER BY time_stamp
SELECT *
FROM your_table
WHERE from_userid = 1 OR to_userid = 1
ORDER by time_stamp
I would do it like this:
select all values + timestamps where "me" is from_userid
select all values + timestamps where "me" is to_userid
in both selects assign the same name to the "other" user id
join the result sets using UNION ALL
then order the result by the timestamp column
group by user id and min(timestamp)
In sql it would be something like this:
select rel_user, min(time_stamp) as first_contact from
(
select time_stamp, to_userid as rel_user where from_userid=my_ID
union all
select time_stamp, from_userid as rel_user where to_userid=my_ID
)
group by rel_user
order by min(time_stamp)
Since all of the other ways use more than one SELECT here's one using CASE
SELECT CASE
WHEN to_userid=1 THEN from_userid
ELSE to_userid
FROM table WHERE to_userid=1 OR from_userid=1 ORDER BY time_stamp

returning Max value of select statement SQL

I pretty much forgot how to do this with SQL actually, the thing is I have an SQL select statement such as:
SELECT COUNT(*) NAME FROM `SomeTable` WHERE `SomeID` = xxx GROUP BY `Field`
Which does return a table with one field and many records containing numbers. What I want is to get the a single value of the maximum number among those records.
it should help you. just use MAX() function
SELECT MAX(COUNT(*)) FROM `SomeTable` WHERE `SomeID` = xxx GROUP BY `Field`
Just add LIMIT:
SELECT COUNT(`NAME`) AS `NUM` FROM `SomeTable` WHERE `SomeID` = xxx GROUP BY `Field` ORDER BY `NUM` DESC LIMIT 1
select max(name) from
(
SELECT COUNT(*) NAME FROM `SomeTable` WHERE `SomeID` = xxx GROUP BY `Field`)a
SELECT COUNT(*) NAME
FROM `SomeTable`
WHERE `SomeID` = xxx
GROUP BY `Field`
order by NAME desc
limit 1
I want is to get the a single value of the maximum number among those
records.
Try this:
SELECT t1.*
FROM SomeTable t1
(
SELECT SomeID, Max(Field) MaxField
FROM SomeTable
GROUP BY SomeID
) t2 ON t1.SomeID = t2.SomeID AND t1.Field = t2.MaxField
WHERE t1.SomeID = xxx
The syntax for the MAX function is:
SELECT MAX(expression )
FROM tables
WHERE predicates;
Example
SELECT MAX(salary) as "Highest salary"
FROM employees;
If you just want a single result of the highest value against a filter, just use Max:
SELECT MAX(MyField) NAME
FROM `SomeTable`
WHERE `SomeID` = xxx;
Alternatively, if you want an aggregate grouped by another column, the syntax is like so:
SELECT Name, MAX(MyField) as MaxOfMyField -- Or COUNT(MyField) if you want the Count
FROM `SomeTable`
WHERE `SomeID` = xxx
GROUP By Name;

MySQL - match post code based on one or two first characters

I'm trying to create a SQL statement to find the matching record based on the provided post code and stored post codes in the database plus the weight aspect.
The post codes in the database are between 1 or 2 characters i.e. B, BA ...
Now - the value passed to the SQL statement will always have 2 first characters of the client's post code. How can I find the match for it? Say I have a post code B1, which would only match the single B in the database plus the weight aspect, which I'm ok with.
Here's my current SQL statement, which also takes the factor of the free shipping above certain weight:
SELECT `s`.*,
IF (
'{$weight}' > (
SELECT MAX(`weight_from`)
FROM `shipping`
WHERE UPPER(SUBSTRING(`post_code`, 1, 2)) = 'B1'
),
(
SELECT `cost`
FROM `shipping`
WHERE UPPER(SUBSTRING(`post_code`, 1, 2)) = 'B1'
ORDER BY `weight_from` DESC
LIMIT 0, 1
),
`s`.`cost`
) AS `cost`
FROM `shipping` `s`
WHERE UPPER(SUBSTRING(`s`.`post_code`, 1, 2)) = 'B1'
AND
(
(
'{$weight}' > (
SELECT MAX(`weight_from`)
FROM `shipping`
WHERE UPPER(SUBSTRING(`post_code`, 1, 2)) = 'B1'
)
)
OR
('{$weight}' BETWEEN `s`.`weight_from` AND `s`.`weight_to`)
)
LIMIT 0, 1
The above however uses the SUBSTRING() function with hard coded number of characters set to 2 - this is where I need some help really to make it match only number of characters that matches the provided post code - in this case B1.
Marcus - thanks for the help - outstanding example - here's what my code look like for those who also wonder:
First I've run the following statement to get the right post code:
(
SELECT `post_code`
FROM `shipping`
WHERE `post_code` = 'B1'
)
UNION
(
SELECT `post_code`
FROM `shipping`
WHERE `post_code` = SUBSTRING('B1', 1, 1)
)
ORDER BY `post_code` DESC
LIMIT 0, 1
Then, based on the returned value assigned to the 'post_code' index my second statement followed with:
$post_code = $result['post_code'];
SELECT `s`.*,
IF (
'1000' > (
SELECT MAX(`weight_from`)
FROM `shipping`
WHERE `post_code` = '{$post_code}'
),
(
SELECT `cost`
FROM `shipping`
WHERE `post_code` = '{$post_code}'
ORDER BY `weight_from` DESC
LIMIT 0, 1
),
`s`.`cost`
) AS `cost`
FROM `shipping` `s`
WHERE `s`.`post_code` = '{$post_code}'
AND
(
(
'1000' > (
SELECT MAX(`weight_from`)
FROM `shipping`
WHERE `post_code` = '{$post_code}'
ORDER BY LENGTH(`post_code`) DESC
)
)
OR
('1000' BETWEEN `s`.`weight_from` AND `s`.`weight_to`)
)
LIMIT 0, 1
The following query will get all results where the post_code in the shipping table matches the beginning of the passed in post_code, then it orders it most explicit to least explicit, returning the most explicit one:
SELECT *
FROM shipping
WHERE post_code = SUBSTRING('B1', 1, LENGTH(post_code))
ORDER BY LENGTH(post_code) DESC
LIMIT 1
Update
While this query is flexible, it's not very fast, since it can't utilize an index. If the shipping table is large, and you'll only pass in up to two characters, it might be faster to make two separate calls.
First, try the most explicit call.
SELECT *
FROM shipping
WHERE post_code = 'B1'
If it doesn't return a result then search on a single character:
SELECT *
FROM shipping
WHERE post_code = SUBSTRING('B1', 1, 1)
Of course, you can combine these with a UNION if you must do it in a single call:
SELECT * FROM
((SELECT *
FROM shipping
WHERE post_code = 'B1')
UNION
(SELECT *
FROM shipping
WHERE post_code = SUBSTRING('B1', 1, 1))) a
ORDER BY post_code DESC
LIMIT 1