Mysql Export in sql format with custom where condition - mysql

I have requirement in my project to extract the rows in sql format. I have multiple select statements with same WHERE condition. Is it possible to set the WHERE condition in a param and make use of it in the select statements?
#set maxrows -1;
#export on;
#export set filename="C:\test\test12.sql" appendfile="true" format="sql";
SELECT ee.employeeId, ee.firstname, ee.lastName, ee.designation
FROM employee ee
WHERE ee.employeeId in (1, 2, 3, 4);
SELECT lib.employeeId, lib.bookId
FROM library lib
WHERE lib.employeeId in (1, 2, 3, 4);
SELECT lv.employeeId, lv.LeaveApplicationDate, lv.NoOfLeaves
FROM Leaves lv
WHERE lv.employeeId in (1, 2, 3, 4);
#export off;
As you can observe here, the WHERE condition is constant for each of SELECT Statements.
Is it possible to set in a param and make use of the same in all the select statements?
Example (below will not work):
#set maxrows -1;
#set employeeIds = 1, 2, 3, 4;
#export on;
#export set filename="c:\Work\test124536.sql" appendfile="true" format="sql";
SELECT ee.employeeId, ee.firstname, ee.lastName, ee.designation
FROM employee ee
WHERE ee.employeeId in (employeeIds);
#export off;

Related

How to fix 'subquery returns more than 1 row' with variable tables

I have a table RAW_SCORES that contains a bunch of homework/exam grades. There is a row in RAW_SCORES that contains the max points for each assignment.
('6410', 'Rivera', 'Rhonda', '315', 64, 64, 28, 85, 98, 152),
('0001', 'MAX', 'POINTS', '415', 100, 80, 32, 100, 120, 200),
I want to create a procedure that prints a table with the (Raw Score / Max Score) for each assignment. So for assignment 1:
SET hw1M = (SELECT HW1 FROM RAW_SCORES WHERE (SSN = '0001'));
SELECT RAW_SCORES.SSN,
RAW_SCORES.FName,
RAW_SCORES.LName,
ROUND(RAW_SCORES.HW1 / hw1M, 2)
FROM RAW_SCORES WHERE NOT (RAW_SCORES.SSN = '0001' OR RAW_SCORES.SSN = '0002');
Gives me the correct result for HW1, but the table header says Round(bla bla bla) and the question wants it to be printed as HW1Pct. So I tried:
SET hw1M = (SELECT HW1 FROM RAW_SCORES WHERE (SSN = '0001'));
SET HW1Pct = (SELECT ROUND(RAW_SCORES.HW1 / hw1M, 2) FROM RAW_SCORES WHERE hw1M IN (SELECT HW1 FROM RAW_SCORES WHERE (SSN = '0001')));
SELECT RAW_SCORES.SSN,
RAW_SCORES.FName,
RAW_SCORES.LName,
HW1Pct
FROM RAW_SCORES WHERE NOT (RAW_SCORES.SSN = '0001' OR RAW_SCORES.SSN = '0002');
But this gives me the Subquery returns more than 1 row error. Most of the other answers to this error are a JOIN statement, but I'm not sure how I would implement that in my case. Any help is appreciated. Sorry for it being a dumb question.
Just add a column alias to your original query:
ROUND(RAW_SCORES.HW1 / hw1M, 2) AS HW1Pct
See the manual

MySQL Adding two binary values stored in user defined variables

I have a SQL script....
SET #lat = 0;
SET #lat = (SELECT (CONV(SUBSTRING(data, 5,8),16,2)) FROM transaction_wtrax WHERE `show` = 0);
SET #lat = REPLACE(#lat, 1, 2);
SET #lat = REPLACE(#lat, 0, 1);
SET #lat = REPLACE(#lat, 2, 0);
The above results in a binary value for #lat.
I would like to add the value 1 to #lat.
I can add two binary literals by preceding the values with 0b
ie. Select 0b10001 + 0b1 (this works 100%)
however the following fails to add binary when you are working with user defined variables ...
Select #lat + 0b1 or Select Concat('0b', #lat) + 0b1 (this does not work)
How can I add my #lat to 0b1?
Thank you.
You can use CONV to convert it to decimal, do the add and then convert back to binary. CONV doesn't mind if its input value is an integer or a string.
SELECT CONV(CONV(#lat, 2, 10) + 1, 10, 2)
e.g.
SELECT CONV(CONV('00000100100011001110000001000111',2,10)+1,10,2)
Output:
100100011001110000001001000

How to generate a UUIDv4 in MySQL?

MySQL's UUID function returns a UUIDv1 GUID. I'm looking for an easy way to generate random GUIDs (i.e. UUIDv4) in SQL.
I've spent quite some time looking for a solution and came up with the following
mysql function that generates a random UUID (i.e. UUIDv4) using standard MySQL
functions. I'm answering my own question to share that in the hope that it'll be
useful.
-- Change delimiter so that the function body doesn't end the function declaration
DELIMITER //
CREATE FUNCTION uuid_v4()
RETURNS CHAR(36) NO SQL
BEGIN
-- Generate 8 2-byte strings that we will combine into a UUIDv4
SET #h1 = LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0');
SET #h2 = LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0');
SET #h3 = LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0');
SET #h6 = LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0');
SET #h7 = LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0');
SET #h8 = LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0');
-- 4th section will start with a 4 indicating the version
SET #h4 = CONCAT('4', LPAD(HEX(FLOOR(RAND() * 0x0fff)), 3, '0'));
-- 5th section first half-byte can only be 8, 9 A or B
SET #h5 = CONCAT(HEX(FLOOR(RAND() * 4 + 8)),
LPAD(HEX(FLOOR(RAND() * 0x0fff)), 3, '0'));
-- Build the complete UUID
RETURN LOWER(CONCAT(
#h1, #h2, '-', #h3, '-', #h4, '-', #h5, '-', #h6, #h7, #h8
));
END
//
-- Switch back the delimiter
DELIMITER ;
Note: The pseudo-random number generation used (MySQL's RAND) is not
cryptographically secure and thus has some bias which can increase the collision
risk.
Both existing answers relies on MySQL RAND() function:
RAND() is not meant to be a perfect random generator. It is a fast way to generate random numbers on demand that is portable between platforms for the same MySQL version.
In the practice, this mean that the generated UUID using this function might (and will) be biased, and collisions can occur more frequently then expected.
Solution
It's possible to generate safe UUID V4 on MySQL side using random_bytes() function:
This function returns a binary string of len random bytes generated using the random number generator of the SSL library.
So we can update the function to:
CREATE FUNCTION uuid_v4s()
RETURNS CHAR(36)
BEGIN
-- 1th and 2nd block are made of 6 random bytes
SET #h1 = HEX(RANDOM_BYTES(4));
SET #h2 = HEX(RANDOM_BYTES(2));
-- 3th block will start with a 4 indicating the version, remaining is random
SET #h3 = SUBSTR(HEX(RANDOM_BYTES(2)), 2, 3);
-- 4th block first nibble can only be 8, 9 A or B, remaining is random
SET #h4 = CONCAT(HEX(FLOOR(ASCII(RANDOM_BYTES(1)) / 64)+8),
SUBSTR(HEX(RANDOM_BYTES(2)), 2, 3));
-- 5th block is made of 6 random bytes
SET #h5 = HEX(RANDOM_BYTES(6));
-- Build the complete UUID
RETURN LOWER(CONCAT(
#h1, '-', #h2, '-4', #h3, '-', #h4, '-', #h5
));
END
This should generate UUID V4 random enough to don't care about collisions.
NOTE: Unfortunately MariaDB doesn't support RANDOM_BYTES() (See https://mariadb.com/kb/en/function-differences-between-mariadb-105-and-mysql-80/#miscellaneous)
Test
I've created following test scenario: Insert random UUID v4 as primary key for a table until 40.000.000 rows are created. When a collision is found, the row is updated incrementing collisions column:
INSERT INTO test (uuid) VALUES (uuid_v4()) ON DUPLICATE KEY UPDATE collisions=collisions+1;
The sum of collisions after 40 million rows with each function is:
+----------+----------------+
| RAND() | RANDOM_BYTES() |
+----------+----------------+
| 55 | 0 |
+----------+----------------+
The number collisions in both scenarios tends to increase as number of rows grows.
In the off chance you're working with a DB and don't have perms to create functions, here's the same version as above that works just as a SQL expression:
SELECT LOWER(CONCAT(
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'),
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'), '-',
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'), '-',
'4',
LPAD(HEX(FLOOR(RAND() * 0x0fff)), 3, '0'), '-',
HEX(FLOOR(RAND() * 4 + 8)),
LPAD(HEX(FLOOR(RAND() * 0x0fff)), 3, '0'), '-',
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'),
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'),
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0')));
Adaptation of Elias Soares's answer using RANDOM_BYTES without creating a DB function:
SELECT LOWER(CONCAT(
HEX(RANDOM_BYTES(4)), '-',
HEX(RANDOM_BYTES(2)), '-4',
SUBSTR(HEX(RANDOM_BYTES(2)), 2, 3), '-',
CONCAT(HEX(FLOOR(ASCII(RANDOM_BYTES(1)) / 64)+8),SUBSTR(HEX(RANDOM_BYTES(2)), 2, 3)), '-',
HEX(RANDOM_BYTES(6))
))

ORDER BY Color with Hex Code as a criterio in MySQL

I have a table that contains color options for a product. The color options include a hex color code, which is used to generate the UI (HTML).
I would like to sort the rows so that the colors in the UI look like a rainbow, instead of the current order that sorts based off of the Name of the color (not very useful).
Here is what my query looks like. I get the R G B decimal values from the hex code. I just don't know how to order it.
I've looked into color difference algorithms. They seem more useful to compare 2 colors' similarity, not sort.
I'm using MySQL:
select a.*, (a.c_r + a.c_g + a.c_b) color_sum
from (
select co.customization_option_id,
co.designer_image_url,
concat(co.name, " (",cog.name, ")") name,
co.customization_option_group_id gr,
designer_hex_color,
conv(substr(designer_hex_color, 1, 2), 16, 10) c_r,
conv(substr(designer_hex_color, 3, 2), 16, 10) c_g,
conv(substr(designer_hex_color, 5, 2), 16, 10) c_b
from customization_options co
left join customization_option_groups cog
on cog.id = co.customization_option_group_id
where co.customization_id = 155
and co.customization_option_group_id
in (1,2,3,4)) a
order by ????
You want to sort hex codes by wavelength, this roughly maps onto the hue-value. Given a hexcode as a six character string: RRGGBB.
You just need to make a function that takes in a hexcode string and outputs the hue value, here's the formula from this Math.SO answer:
R' = R/255
G' = G/255
B' = B/255
Cmax = max(R', G', B')
Cmin = min(R', G', B')
Δ = Cmax - Cmin
I wanted to see if this would work, so I whipped up a sample program in Ruby, it samples 200 random colors uniformly from RGB-space, and sorts them, the output looks like a rainbow!
Here's the Ruby source:
require 'paint'
def hex_to_rgb(hex)
/(?<r>..)(?<g>..)(?<b>..)/ =~ hex
[r,g,b].map {|cs| cs.to_i(16) }
end
def rgb_to_hue(r,g,b)
# normalize r, g and b
r_ = r / 255.0
g_ = g / 255.0
b_ = b / 255.0
c_min = [r_,g_,b_].min
c_max = [r_,g_,b_].max
delta = (c_max - c_min).to_f
# compute hue
hue = 60 * ((g_ - b_)/delta % 6) if c_max == r_
hue = 60 * ((b_ - r_)/delta + 2) if c_max == g_
hue = 60 * ((r_ - g_)/delta + 4) if c_max == b_
return hue
end
# sample uniformly at random from RGB space
colors = 200.times.map { (0..255).to_a.sample(3).map { |i| i.to_s(16).rjust(2, '0')}.join }
# sort by hue
colors.sort_by { |color| rgb_to_hue(*hex_to_rgb(color)) }.each do |color|
puts Paint[color, color]
end
Note, make sure to gem install paint to get the colored text output.
Here's the output:
It should be relatively straight-forward to write this as a SQL user-defined function and ORDER BY RGB_to_HUE(hex_color_code), however, my SQL knowledge is pretty basic.
EDIT: I posted this question on dba.SE about converting the Ruby to a SQL user defined function.
This is based on the answer by #dliff. I initially edited it, but it turns out my edit was rejected saying "it should have been written as a comment or an answer". Seeing this would be too large to post as a comment, here goes.
The reason for editing (and now posting) is this: there seems to be a problem with colors like 808080 because their R, G and B channels are equal. If one needs this to sort or group colors and keep the passed grayscale/non-colors separate, that answer won't work, so I edited it.
DELIMITER $$
DROP FUNCTION IF EXISTS `hex_to_hue`$$
CREATE FUNCTION `hex_to_hue`(HEX VARCHAR(6)) RETURNS FLOAT
BEGIN
DECLARE r FLOAT;
DECLARE b FLOAT;
DECLARE g FLOAT;
DECLARE MIN FLOAT;
DECLARE MAX FLOAT;
DECLARE delta FLOAT;
DECLARE hue FLOAT;
IF(HEX = '') THEN
RETURN NULL;
END IF;
SET r = CONV(SUBSTR(HEX, 1, 2), 16, 10)/255.0;
SET g = CONV(SUBSTR(HEX, 3, 2), 16, 10)/255.0;
SET b = CONV(SUBSTR(HEX, 5, 2), 16, 10)/255.0;
SET MAX = GREATEST(r,g,b);
SET MIN = LEAST(r,g,b);
SET delta = MAX - MIN;
SET hue=
(CASE
WHEN MAX=r THEN (60 * ((g - b)/delta % 6))
WHEN MAX=g THEN (60 * ((b - r)/delta + 2))
WHEN MAX=b THEN (60 * ((r - g)/delta + 4))
ELSE NULL
END);
IF(ISNULL(hue)) THEN
SET hue=999;
END IF;
RETURN hue;
END$$
DELIMITER ;
Again, I initially wanted to edit the original answer, not post as a separate one.
If your products can have lots of color probably a good UI will require a color picker, normally those are rectangular, so not really something possible with the order by.
If the products have a manageable number of colors you have different choice, the easiest to implement is an order table, where for every possible color is defined an order position, this table can then be joined to your query, something like
SELECT ...
FROM (SELECT ...
...
...
, ci.color_order
FROM customization_options co
LEFT JOIN customization_option_groups cog
ON cog.id = co.customization_option_group_id
LEFT JOIN color_ ci
ON designer_hex_color = ci.color
WHERE ...) a
ORDER BY color_order
Another way to go is to transform the RGB color to hue and use this as the order.
There are different formula for this conversion, depending on wich order you want the primary color to have, all of them can be found on the wikipedia page for hue, I can update the answer to help you convert one of those to T-SQL, if needed.
MySQL function Hex to Hue. Based on Tobi's answer. :)
CREATE FUNCTION `hex_to_hue`(hex varchar(6)) RETURNS float
BEGIN
declare r float;
declare b float;
declare g float;
declare min float;
declare max float;
declare delta float;
declare hue float;
set r = conv(substr(hex, 1, 2), 16, 10)/255.0;
set g = conv(substr(hex, 3, 2), 16, 10)/255.0;
set b = conv(substr(hex, 5, 2), 16, 10)/255.0;
set max = greatest(r,g,b);
set min = least(r,g,b);
set delta = max - min;
set hue=
(case
when max=r then (60 * ((g - b)/delta % 6))
when max=g then (60 * ((b - r)/delta + 2))
when max=b then (60 * ((r - g)/delta + 4))
else null
end);
RETURN hue;
END

How to get an ordered list of rows within 0 value with sql?

For example:
SELECT * FROM atable ORDER BY num;
'atable' is:
num name
1 a
3 y
0 cc
2 fs
The result is:
num name
1 a
2 fs
3 y
0 cc
But I want it to be:
num name
0 cc
1 a
2 fs
3 y
I can't reproduce the result you are seeing. The query that you posted should work as you wish it to. Here's my steps to reproduce:
CREATE TABLE atable (num INT NOT NULL, name NVARCHAR(100) NOT NULL);
INSERT INTO atable (num, name) VALUES
(1, 'a'),
(3, 'y'),
(0, 'cc'),
(2, 'fs');
SELECT * FROM atable ORDER BY num;
Result:
0, 'cc'
1, 'a'
2, 'fs'
3, 'y'
Perhaps you could post your create scripts for your table and test data in your question so that we can reproduce your result?
Are you sure that the 0 isn't a null value being displayed as a 0? Nulls can sort either at the top or the bottom, depending on database setting.
SELECT * FROM atable
ORDER BY ISNULL(CAST(num as int), 0);