Two things to do in MySQL IF() - mysql

I have a problem concerning the IF() function in MySQL.
I would like to return a string and change the value of a variable. Somwhat like:
IF(#firstRow=1, "Dear" AND #firstRow:=0, "dear")
This outputs only '0' instead of 'Dear'...
I would be very thankful for some input on ways I could solve this problem!
Louis :)

AND is a boolean operator, not a "also do this other thing" operator.
"Dear" AND 0 returns 0 because 0 is treated as false in MySQL and <anything> AND false will return false.
Also because the integer/boolean value of "Dear" is 0 as well. Using a string in a numeric context just reads initial digits in the string, if any, and ignores the rest.
It's not clear what your problem is, but I guess you want to capitalize the word "dear" if the row is the first one in the result set.
Instead of being too clever by half trying to fit the side-effect into your expression, do yourself a favor and break it out into a separate column:
mysql> SELECT IF(#firstRow=1, 'Dear', 'dear'), #firstRow:=0 AS _ignoreThis
-> FROM (SELECT #firstRow:=1) AS _init
-> CROSS JOIN
-> mytable;
+---------------------------------+-------------+
| IF(#firstRow=1, 'Dear', 'dear') | _ignoreThis |
+---------------------------------+-------------+
| Dear | 0 |
| dear | 0 |
| dear | 0 |
+---------------------------------+-------------+
But if you really want to make your code as confusing and unreadable as possible, you can do something like this:
SELECT IF(#firstRow=1, CONCAT('Dear', IF(#firstRow:=0, '', '')), 'dear')
FROM (SELECT #firstRow:=1) AS _init
CROSS JOIN
...
But remember this important metric of code quality: WTFs per minute.

Use a case expression instead of IF() as the syntax is far easier to follow e.g.
select
case when #firstRow = 1 then 'Dear' else 'dear' end AS Salutation
, #firstRow := 0
from (
select 1 n union all
select 2 n union all
select 3
) d
cross join (SELECT #firstRow:=1) var
+---+------------+----------------+
| | Salutation | #firstRow := 0 |
+---+------------+----------------+
| 1 | Dear | 0 |
| 2 | dear | 0 |
| 3 | dear | 0 |
+---+------------+----------------+
Demo

Related

Creating a column being the multiple of others

I need some help. I have 2 colluns from mysql query result: 1 with text, and another with decimal values. Like that:
select desc, value from table a
|5,50 % | 2984.59 |
|Subs | 10951.70 |
|Isent | 3973.17 |
|13,30 % | 560.26 |
From the rows that have the %, I want to multiply the values and create a third result column, rounding up to two decimal places. See above
2984,59 * 0,055 = 164,15245
560,26 * 0,133 = 74,514
I need make the sql query that show something like above.
+-------+-----------+-----------+
|5,50 % | 2984,59 | 164,16 |
|Subs | 10951,70 | 0 or NULL |
|Isent | 3973,17 | 0 or NULL |
|13,30% | 560,26 | 74,52 |
+-------+-----------+-----------+
How i can do it?
Thanks so much for help
It would be better to have floaring numbers in the first place, converting costs time
You have commas in your procentage, but mysql needs dots there
If value isn't always a number, you can use the mysql way to add a 0 0 to it, that remioves all non numerical characters
SELECT `desc`, `value`, (REPLACE(`desc`,',','.') + 0) * `value` / 100 FROM val
desc
value
(REPLACE(`desc`,',','.') + 0) * `value` / 100
5,50 %
2985
164.175
Subs
10952
0
Isent
3973
0
13,30 %
560
74.48
fiddle
SELECT `desc`, `value`, CEIL((REPLACE(`desc`,',','.') + 0) * `value`) / 100 FROM val
desc
value
CEIL((REPLACE(`desc`,',','.') + 0) * `value`) / 100
5,50 %
2985
164.18
Subs
10952
0
Isent
3973
0
13,30 %
560
74.48
fiddle

Loading quoted numbers into snowflake table from CSV with COPY TO <TABLE>

I have a problem with loading CSV data into snowflake table. Fields are wrapped in double quote marks and hence there is problem with importing them into table.
I know that COPY TO has CSV specific option FIELD_OPTIONALLY_ENCLOSED_BY = '"'but it's not working at all.
Here are some pices of table definition and copy command:
CREATE TABLE ...
(
GamePlayId NUMBER NOT NULL,
etc...
....);
COPY INTO ...
FROM ...csv.gz'
FILE_FORMAT = (TYPE = CSV
STRIP_NULL_VALUES = TRUE
FIELD_DELIMITER = ','
SKIP_HEADER = 1
error_on_column_count_mismatch=false
FIELD_OPTIONALLY_ENCLOSED_BY = '"'
)
ON_ERROR = "ABORT_STATEMENT"
;
Csv file looks like this:
"3922000","14733370","57256","2","3","2","2","2019-05-23 14:14:44",",00000000",",00000000",",00000000",",00000000","1000,00000000","1000,00000000","1317,50400000","1166,50000000",",00000000",",00000000",",00000000",",00000000",",00000000",",00000000",",00000000",",00000000",",00000000",",00000000",",00000000",",00000000",",00000000",",00000000",",00000000",",00000000"
I get an error
'''Numeric value '"3922000"' is not recognized '''
I'm pretty sure it's because NUMBER value is interpreted as string when snowflake is reading "" marks, but since I use
FIELD_OPTIONALLY_ENCLOSED_BY = '"'
it shouldn't even be there... Does anyone have some solution to this?
Maybe something is incorrect with your file? I was just able to run the following without issue.
1. create the test table:
CREATE OR REPLACE TABLE
dbNameHere.schemaNameHere.stacko_58322339 (
num1 NUMBER,
num2 NUMBER,
num3 NUMBER);
2. create test file, contents as follows
1,2,3
"3922000","14733370","57256"
3,"2",1
4,5,"6"
3. create stage and put file in stage
4. run the following copy command
COPY INTO dbNameHere.schemaNameHere.STACKO_58322339
FROM #stageNameHere/stacko_58322339.csv.gz
FILE_FORMAT = (TYPE = CSV
STRIP_NULL_VALUES = TRUE
FIELD_DELIMITER = ','
SKIP_HEADER = 0
ERROR_ON_COLUMN_COUNT_MISMATCH=FALSE
FIELD_OPTIONALLY_ENCLOSED_BY = '"'
)
ON_ERROR = "CONTINUE";
4. results
+-----------------------------------------------------+--------+-------------+-------------+-------------+-------------+-------------+------------------+-----------------------+-------------------------+
| file | status | rows_parsed | rows_loaded | error_limit | errors_seen | first_error | first_error_line | first_error_character | first_error_column_name |
|-----------------------------------------------------+--------+-------------+-------------+-------------+-------------+-------------+------------------+-----------------------+-------------------------|
| stageNameHere/stacko_58322339.csv.gz | LOADED | 4 | 4 | 4 | 0 | NULL | NULL | NULL | NULL |
+-----------------------------------------------------+--------+-------------+-------------+-------------+-------------+-------------+------------------+-----------------------+-------------------------+
1 Row(s) produced. Time Elapsed: 2.436s
5. view the records
>SELECT * FROM dbNameHere.schemaNameHere.stacko_58322339;
+---------+----------+-------+
| NUM1 | NUM2 | NUM3 |
|---------+----------+-------|
| 1 | 2 | 3 |
| 3922000 | 14733370 | 57256 |
| 3 | 2 | 1 |
| 4 | 5 | 6 |
+---------+----------+-------+
Can you try with a similar test as this?
EDIT: A quick look at your data shows many of your numeric fields appear to start with commas, so something definitely amiss with the data.
Assuming your numbers are European formatted , decimal place, and . thousands, reading the numeric formating help, it seems Snowflake does not support this as input. I'd open a feature request.
But if you read the column in as text then use REPLACE like
SELECT '100,1234'::text as A
,REPLACE(A,',','.') as B
,TRY_TO_DECIMAL(b, 20,10 ) as C;
gives:
A B C
100,1234 100.1234 100.1234000000
safer would be to strip placeholders first like
SELECT '1.100,1234'::text as A
,REPLACE(A,'.') as B
,REPLACE(B,',','.') as C
,TRY_TO_DECIMAL(C, 20,10 ) as D;

MySql XNOR equivalent

I'm writing a SQL query which checks for incorrect equipment in its where clause. In order to perform this operation I need to check each of the equipment's revision cycles one by one, so this clause would limit the results to correct equipment (not having any of the cycles incorrect):
where not exists(select * from trevision_cycle cycle
where cycle.id_equipment = equip.id and cycle.`status` = 'NO_OK')
However, now I want to introduce a query parameter in order to retrieve only the correct equipment or only the incorrect equipment, depending on its value. Let's say I call it incorrect, so I would like to do the same as what's done here:
where (not incorrect and not exists(select * from trevision_cycle cycle
where cycle.id_equipment = equip.id and cycle.`status` = 'NO_OK'))
or (incorrect and exists (select * from trevision_cycle cycle
where cycle.id_equipment = equip.id and cycle.`status` = 'NO_OK'))
So, if the incorrect flag is present, check for equipment having at least one incorrect revision cycle. Otherwise, retrieve only the equipment having all of them correct. The query looks quite redundant though and the same result could be achieved with a logical XNOR.
Do I have a better choice for this?
Update
Sample data
Equipment 1 -> Has one NO_OK cycle
Equipment 2 -> All its cycles are OK
Query with incorrect = true -> Returns only Equipment 1
Query with incorrect = false -> Returns only Equipment 2
You can combine XOR with NOT - both exists in mysql. This is truth table for XOR:
+----------------+
|A | B | A XOR B |
+--+---+---------+
|0 | 0 | 0 |
|0 | 1 | 1 |
|1 | 0 | 1 |
|1 | 1 | 0 |
+----------------+
If we apply NOT to this table, it will look this:
+---------------------+
|A | B | NOT(A XOR B) |
+--+---+--------------+
|0 | 0 | 1 |
|0 | 1 | 0 |
|1 | 0 | 0 |
|1 | 1 | 1 |
+---------------------+
Same as the XNOR table. So, WHERE can look like this:
WHERE NOT (incorrect XOR EXISTS(SELECT * FROM trevision_cycle cycle
WHERE cycle.id_equipment = equip.id AND cycle.`status` = 'NO_OK'))
Referencing This Fellow's blog, if you were to create the function XNOR like so:
--XNOR
CREATE FUNCTION XNOR (#a bit, #b bit) RETURNS bit AS
BEGIN
RETURN #a ^ #b ^ 1
END
Then you could simplify your statement using it as so:
where dbo.XNOR(incorrect, exists(select * from trevision_cycle cycle
where cycle.id_equipment = equip.id and cycle.`status` = 'NO_OK'))
EDIT: My apologies, for MySQL, you would have to create the function using its XOR instead of '^' ('^' is the XOR function for SQL Server). I'm uncertain if the rest of the syntax is correct for MySQL, but you get the idea:
--XNOR
CREATE FUNCTION XNOR (#a bit, #b bit) RETURNS bit AS
BEGIN
RETURN #a XOR #b XOR 1
END
If you have reason not to make up a new function to do this, then the following is logically equivalent:
where incorrect XOR exists(select * from trevision_cycle cycle
where cycle.id_equipment = equip.id and cycle.`status` = 'NO_OK') XOR 1

Is there a way to merge boolean value fields in MySQL?

I have a table that contains several fields with Boolean values.
I need 3 of the fields to be merged into one only if all 3 of them are true.
I was thinking about a JOIN, but it looks like it cannot do what I need.
------------------------------------------------------------
| Email address| permission1 | permission2 | permission3
------------------------------------------------------------
| test#test.com| 1 | 0 | 1
------------------------------------------------------------
| test2#test.com| 1 | 1 | 1
------------------------------------------------------------
I would expect a result, perhaps in a new table to look like this:
--------------------------------
| Email address| permissionMerge
--------------------------------
| test#test.com| 0 |
--------------------------------
| test2#test.com| 1 |
--------------------------------
You could use CASE syntax
SELECT `email address`,
CASE WHEN `permission1` = 1
AND `permission2` = 1
AND `permission3` = 1
THEN 1
ELSE 0 END AS 'permissionMerge'
FROM `Table`
You could also do it that way:
SELECT `email address`,
CASE WHEN SUM(`permission1`,`permission2`,`permission3`) = 3
THEN 1
ELSE 0 END AS 'permissionMerge'
FROM `Table`
GROUP BY `email address`
Select `Email adderss`,(permission1 and permission2 and permission3) as permissionMerge from table
Depending on the quality of data, you could get away with something as simple as:
SELECT address,
CASE SUM(permission1, permission2, permission3)
WHEN 3 THEN 1
ELSE 0
END AS permissionMerge
FROM undisclosed_table
... or you'll need something more robust:
SELECT address,
CASE
WHEN permission1 IS TRUE AND permission2 IS TRUE AND permission3 IS TRUE THEN 1
ELSE 0
END AS permissionMerge
FROM undisclosed_table
You can generate a new table with:
CREATE TABLE table_with_duplicate_data
SELECT address,
CASE
WHEN permission1 IS TRUE AND permission2 IS TRUE AND permission3 IS TRUE THEN 1
ELSE 0
END AS permissionMerge
FROM undisclosed_table
... thought I'd advise against it: it'll just waste storage and you need to keep data up-to-date. If it's too much typing, you can create a view or (since MySQL/5.7.5) a generated column.

How do I check to see if a value is an integer in MySQL?

I see that within MySQL there are Cast() and Convert() functions to create integers from values, but is there any way to check to see if a value is an integer? Something like is_int() in PHP is what I am looking for.
I'll assume you want to check a string value. One nice way is the REGEXP operator, matching the string to a regular expression. Simply do
select field from table where field REGEXP '^-?[0-9]+$';
this is reasonably fast. If your field is numeric, just test for
ceil(field) = field
instead.
Match it against a regular expression.
c.f. http://forums.mysql.com/read.php?60,1907,38488#msg-38488 as quoted below:
Re: IsNumeric() clause in MySQL??
Posted by: kevinclark ()
Date: August 08, 2005 01:01PM
I agree. Here is a function I created for MySQL 5:
CREATE FUNCTION IsNumeric (sIn varchar(1024)) RETURNS tinyint
RETURN sIn REGEXP '^(-|\\+){0,1}([0-9]+\\.[0-9]*|[0-9]*\\.[0-9]+|[0-9]+)$';
This allows for an optional plus/minus sign at the beginning, one optional decimal point, and the rest numeric digits.
Suppose we have column with alphanumeric field having entries like
a41q
1458
xwe8
1475
asde
9582
.
.
.
.
.
qe84
and you want highest numeric value from this db column (in this case it is 9582) then this query will help you
SELECT Max(column_name) from table_name where column_name REGEXP '^[0-9]+$'
Here is the simple solution for it
assuming the data type is varchar
select * from calender where year > 0
It will return true if the year is numeric else false
This also works:
CAST( coulmn_value AS UNSIGNED ) // will return 0 if not numeric string.
for example
SELECT CAST('a123' AS UNSIGNED) // returns 0
SELECT CAST('123' AS UNSIGNED) // returns 123 i.e. > 0
To check if a value is Int in Mysql, we can use the following query.
This query will give the rows with Int values
SELECT col1 FROM table WHERE concat('',col * 1) = col;
The best i could think of a variable is a int Is a combination with MySQL's functions CAST() and LENGTH().
This method will work on strings, integers, doubles/floats datatypes.
SELECT (LENGTH(CAST(<data> AS UNSIGNED))) = (LENGTH(<data>)) AS is_int
see demo http://sqlfiddle.com/#!9/ff40cd/44
it will fail if the column has a single character value. if column has
a value 'A' then Cast('A' as UNSIGNED) will evaluate to 0 and
LENGTH(0) will be 1. so LENGTH(Cast('A' as UNSIGNED))=LENGTH(0) will
evaluate to 1=1 => 1
True Waqas Malik totally fogotten to test that case. the patch is.
SELECT <data>, (LENGTH(CAST(<data> AS UNSIGNED))) = CASE WHEN CAST(<data> AS UNSIGNED) = 0 THEN CAST(<data> AS UNSIGNED) ELSE (LENGTH(<data>)) END AS is_int;
Results
**Query #1**
SELECT 1, (LENGTH(CAST(1 AS UNSIGNED))) = CASE WHEN CAST(1 AS UNSIGNED) = 0 THEN CAST(1 AS UNSIGNED) ELSE (LENGTH(1)) END AS is_int;
| 1 | is_int |
| --- | ------ |
| 1 | 1 |
---
**Query #2**
SELECT 1.1, (LENGTH(CAST(1 AS UNSIGNED))) = CASE WHEN CAST(1.1 AS UNSIGNED) = 0 THEN CAST(1.1 AS UNSIGNED) ELSE (LENGTH(1.1)) END AS is_int;
| 1.1 | is_int |
| --- | ------ |
| 1.1 | 0 |
---
**Query #3**
SELECT "1", (LENGTH(CAST("1" AS UNSIGNED))) = CASE WHEN CAST("1" AS UNSIGNED) = 0 THEN CAST("1" AS UNSIGNED) ELSE (LENGTH("1")) END AS is_int;
| 1 | is_int |
| --- | ------ |
| 1 | 1 |
---
**Query #4**
SELECT "1.1", (LENGTH(CAST("1.1" AS UNSIGNED))) = CASE WHEN CAST("1.1" AS UNSIGNED) = 0 THEN CAST("1.1" AS UNSIGNED) ELSE (LENGTH("1.1")) END AS is_int;
| 1.1 | is_int |
| --- | ------ |
| 1.1 | 0 |
---
**Query #5**
SELECT "1a", (LENGTH(CAST("1.1" AS UNSIGNED))) = CASE WHEN CAST("1a" AS UNSIGNED) = 0 THEN CAST("1a" AS UNSIGNED) ELSE (LENGTH("1a")) END AS is_int;
| 1a | is_int |
| --- | ------ |
| 1a | 0 |
---
**Query #6**
SELECT "1.1a", (LENGTH(CAST("1.1a" AS UNSIGNED))) = CASE WHEN CAST("1.1a" AS UNSIGNED) = 0 THEN CAST("1.1a" AS UNSIGNED) ELSE (LENGTH("1.1a")) END AS is_int;
| 1.1a | is_int |
| ---- | ------ |
| 1.1a | 0 |
---
**Query #7**
SELECT "a1", (LENGTH(CAST("1.1a" AS UNSIGNED))) = CASE WHEN CAST("a1" AS UNSIGNED) = 0 THEN CAST("a1" AS UNSIGNED) ELSE (LENGTH("a1")) END AS is_int;
| a1 | is_int |
| --- | ------ |
| a1 | 0 |
---
**Query #8**
SELECT "a1.1", (LENGTH(CAST("a1.1" AS UNSIGNED))) = CASE WHEN CAST("a1.1" AS UNSIGNED) = 0 THEN CAST("a1.1" AS UNSIGNED) ELSE (LENGTH("a1.1")) END AS is_int;
| a1.1 | is_int |
| ---- | ------ |
| a1.1 | 0 |
---
**Query #9**
SELECT "a", (LENGTH(CAST("a" AS UNSIGNED))) = CASE WHEN CAST("a" AS UNSIGNED) = 0 THEN CAST("a" AS UNSIGNED) ELSE (LENGTH("a")) END AS is_int;
| a | is_int |
| --- | ------ |
| a | 0 |
see demo
What about:
WHERE table.field = "0" or CAST(table.field as SIGNED) != 0
to test for numeric and the corrolary:
WHERE table.field != "0" and CAST(table.field as SIGNED) = 0
I have tried using the regular expressions listed above, but they do not work for the following:
SELECT '12 INCHES' REGEXP '^(-|\\+){0,1}([0-9]+\\.[0-9]*|[0-9]*\\.[0-9]+|[0-9]+)$' FROM ...
The above will return 1 (TRUE), meaning the test of the string '12 INCHES' against the regular expression above, returns TRUE. It looks like a number based on the regular expression used above. In this case, because the 12 is at the beginning of the string, the regular expression interprets it as a number.
The following will return the right value (i.e. 0) because the string starts with characters instead of digits
SELECT 'TOP 10' REGEXP '^(-|\\+){0,1}([0-9]+\\.[0-9]*|[0-9]*\\.[0-9]+|[0-9]+)$' FROM ...
The above will return 0 (FALSE) because the beginning of the string is text and not numeric.
However, if you are dealing with strings that have a mix of numbers and letters that begin with a number, you will not get the results you want. REGEXP will interpret the string as a valid number when in fact it is not.
This works well for VARCHAR where it begins with a number or not..
WHERE concat('',fieldname * 1) != fieldname
may have restrictions when you get to the larger NNNNE+- numbers
for me the only thing that works is:
CREATE FUNCTION IsNumeric (SIN VARCHAR(1024)) RETURNS TINYINT
RETURN SIN REGEXP '^(-|\\+){0,1}([0-9]+\\.[0-9]*|[0-9]*\\.[0-9]+|[0-9]+)$';
from kevinclark all other return useless stuff for me in case of 234jk456 or 12 inches