Select random value in SQL - mysql

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.

Related

order by with union in SQL is not working

Is it possible to order when the data comes from many select and union it together? Such as
In this statement, the vouchers data is not showing in the same sequence as I saved on the database, I also tried it with "ORDER BY v_payments.payment_id ASC" but won't be worked
( SELECT order_id as id, order_date as date, ... , time FROM orders WHERE client_code = '$searchId' AND order_status = 1 AND order_date BETWEEN '$start_date' AND '$end_date' ORDER BY time)
UNION
( SELECT vouchers.voucher_id as id, vouchers.payment_date as date, v_payments.account_name as name, ac_balance as oldBalance, v_payments.debit as debitAmount, v_payments.description as descriptions,
vouchers.v_no as v_no, vouchers.v_type as v_type, v_payments.credit as creditAmount, time, zero as tax, zero as freightAmount FROM vouchers INNER JOIN v_payments
ON vouchers.voucher_id = v_payments.voucher_id WHERE v_payments.client_code = '$searchId' AND voucher_status = 1 AND vouchers.payment_date BETWEEN '$start_date' AND '$end_date' ORDER BY v_payments.payment_id ASC , time )
UNION
( SELECT return_id as id, return_date as date, ... , time FROM w_return WHERE client_code = '$searchId' AND w_return_status = 1 AND return_date BETWEEN '$start_date' AND '$end_date' ORDER BY time)
Wrap the sub-select queries in the union within a SELECT
SELECT id, name
FROM
(
SELECT id, name FROM fruits
UNION
SELECT id, name FROM vegetables
)
foods
ORDER BY name
If you want the order to only apply to one of the sub-selects, use parentheses as you are doing.
Note that depending on your DB, the syntax may differ here. And if that's the case, you may get better help by specifying what DB server (MySQL, SQL Server, etc.) you are using and any error messages that result.
You need to put the ORDER BY at the end of the statement i.e. you are ordering the final resultset after union-ing the 3 intermediate resultsets
To use an ORDER BY or LIMIT clause to sort or limit the entire UNION result, parenthesize the individual SELECT statements and place the ORDER BY or LIMIT after the last one. See link below:
ORDER BY and LIMIT in Unions
(SELECT a FROM t1 WHERE a=10 AND B=1)
UNION
(SELECT a FROM t2 WHERE a=11 AND B=2)
ORDER BY a LIMIT 10;

sql order by not working with decimal(18,6)

The SQL query with order by clause is not working properly.
Query:
select cast(actual_qty as decimal(18,2)) from `Bin`
where warehouse = `Warehouse`.name
order by actual_qty desc
Output of above query:
303.00
550.00
0.00
3.00
The type of actual_qty is decimal(18,6). I tried using cast function in order by, didn't work.
Any help is much appreciated!!
Update1:
Here's my full query that is being fired:
select `tabWarehouse`.name, CONCAT_WS(" : ", "Actual Qty", ifnull( ( select round(`tabBin`.actual_qty, 2) as qty
from `tabBin` where `tabBin`.warehouse = `tabWarehouse`.name
and `tabBin`.item_code = '30440'
order by qty desc), 0) ) as actual_qty
from `tabWarehouse` where `tabWarehouse`.`name` like '%%%%' and ifnull(`tabWarehouse`.company, '') in ('', 'TILE TEST') and `tabWarehouse`.is_group = 0.0
limit 0, 20
The output is still the same which is not really ordered by the qty in a descending manner.
Update 2:
This is how my code looks:
query = """select tw.name,
CONCAT_WS(" : ", "Actual Qty", ifnull(round(`tabBin`.actual_qty, 2), 0 ) actual_qty
from `tabWarehouse` tw left join `tabBin` tb
on tb.warehouse = tw.name {bin_conditions}
where
tw.`{key}` like {txt}
{fcond} {mcond}
order by ifnull(round(tb.actual_qty, 2), 0) desc
limit
{start}, {page_len}
""".format(
bin_conditions=get_filters_cond(doctype, filter_dict.get("Bin"),bin_conditions, ignore_permissions=True),
# sub_query=sub_query,
key=searchfield,
fcond=get_filters_cond(doctype, filter_dict.get("Warehouse"), conditions),
mcond=get_match_cond(doctype),
start=start,
page_len=page_len,
txt=frappe.db.escape('%{0}%'.format(txt))
)
The cast in select doesn't change the type of the column -- and the order by is referring to the column in the table, not the expression in the select.
One option is to give it a new name and use that:
select cast(actual_qty as decimal(18,2)) as qty
from `Bin`
where warehouse = `Warehouse`.name
order by qty desc;
Or repeat the expression:
select cast(actual_qty as decimal(18,2)) as qty
from `Bin`
where warehouse = `Warehouse`.name
order by cast(actual_qty as decimal(18,2)) desc
There is no ORDER BY clause in your query.
The ORDER BY inside the correlated subquery is useless because that subquery will work only if it returns only 1 row and does not effect the final results.
Try this:
select tw.name,
CONCAT_WS(" : ", "Actual Qty", ifnull(round(tb.actual_qty, 2), 0)) actual_qty
from tabWarehouse tw left join tabBin tb
on tb.warehouse = tw.name and tb.item_code = '30440'
where tw.name like '%%%%'
and ifnull(tw.company, '') in ('', 'TILE SELECT')
and tw.is_group = 0.0
order by ifnull(round(tb.actual_qty, 2), 0) desc limit 0, 20
Also what is this condition:
`tabWarehouse`.`name` like '%%%%'

Can I concatenate multiple MySQL Column into One Column?

Good day i would like to ask if this is possible in MySQL
SELECT id,label,name,age,sex FROM table LIMIT 3
Output
[row1] id,label,name,age,sex
[row2] id,label,name,age,sex
[row3] id,label,name,age,sex
My Output Needed
[row1] id
[row2] label
[row3] name
[row4] age
[row5] sex
[row6] id
[row7] label
[row8] name
[row9] age
[row10] sex
[row11] id
[row12] label
[row13] name
[row14] age
[row15] sex
You can do something like this:
SELECT * FROM
((SELECT id AS id1, 1 AS rownum, 'id' AS colname, id AS Data_value FROM mytable LIMIT 3)
UNION ALL
(SELECT id, 2, 'label', label FROM mytable LIMIT 3)
UNION ALL
(SELECT id, 3, 'name', name FROM mytable LIMIT 3)
UNION ALL
(SELECT id, 4, 'age', age FROM mytable LIMIT 3)
UNION ALL
(SELECT id, 5, 'sex', sex FROM mytable LIMIT 3)) A
ORDER BY id1, rownum
Here's a fiddle: https://www.db-fiddle.com/f/dvg6x1vBg6H5bDNp9VZxQa/4
I've added 3 additional column id AS id1, rownum and colname. The first two additional column is used for ORDER BY at the outer query. If you don't want to see the additional column, you can just type SELECT Data_value FROM ... at the outer query.
You can use group_concat() to aggregate rows by string concatenation. For the LIMIT to work you then need to use a derived table. But you should be careful with a LIMIT without an ORDER BY. As the order of a query result can be random unless an explicit ORDER BY is issued, you may get different results each time you run the query.
SELECT group_concat(id,
'\n',
label,
'\n',
name,
'\n',
age,
'\n',
sex
SEPARATOR '\n')
FROM (SELECT id,
label,
name,
age,
sex
FROM elbat
LIMIT 3) x;
If you just want to concatenate the columns but keep the rows just use concat().
SELECT concat(id,
'\n',
label,
'\n',
name,
'\n',
age,
'\n',
sex)
FROM elbat
LIMIT 3;
yes,you can use union all like below :
SELECT id FROM table LIMIT 3
union all
SELECT label FROM table LIMIT 3
union all
SELECT name FROM table LIMIT 3
union all
SELECT age FROM table LIMIT 3
union all
SELECT sex FROM table LIMIT 3
That what you looking is to Unpivot data. For more info about pivot and unpivot you can check here.
http://archive.oreilly.com/oreillyschool/courses/dba1/dba110.html
Unfortunately there is no easy way to unpivot in mysql.
The below script will work for MySQL 8.0
set #rowNum :=0;
set #string :=(
select group_concat(id,',',label,',',name,',',age,',',sex separator ',')
from (
select id, label, name, age, sex from mytable limit 3
) x
);
with recursive
R1 as ( select #string as items),
R2 as ( select 1 as n
union
select n + 1 from R2, R1
where n <= length(items) - length(replace(items, ',', '')))
select distinct #rowNum := #rowNum+1 as rowNum, substring_index(substring_index(items, ',', n), ',', -1) output from R2, R1;

SQL : Conditional result used in the same conditional outputs

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

Mysql LEFT to match first 3 chars

Im trying to get all matching records from the invoice_id field where the first 3 characters are RBK, case sensitivity not important. I've tried to use the LEFT function in the bottom 2 ways but its not working. Any ideas on how to achieve this?
SELECT *, IF( LEFT( invoice_id, 3) = 'RBK') FROM `invoices` ORDER BY id ASC
SELECT *, IF( LEFT( invoice_id, 3) = 'RBK', 3, 0) FROM `invoices` ORDER BY id ASC
an if inside the select is not to filter results,if you want to filter result use where clause.
SELECT * FROM `invoices` WHERE LEFT(invoice_id, 3) = "RBK" ORDER BY id ASC