Check character differences in a string using SQL - mysql

In SQL, I have got a column "MyString" representing a string of characters where each character represent different statuses in the lifecycle of a product.
The objective is to write a SQL code which will extract automatically from "MyString" the current status of the product, the previous status of the product as well as their index.
To simulate the context, here is some code:
DECLARE #MyString nvarchar(100) = 'AAABBC'
SELECT
SUBSTRING(#MyString,1,1) as first_status,
CHARINDEX('b',#MyString) AS second_status_index,
SUBSTRING(#MyString,4,1) as second_status,
CHARINDEX('c',#MyString) AS third_status_index;
The idea is to automate this query so that I can re-use it for a number of records but not sure if it's possible.
Expected output:
first_status
second_status_index
second_status
third_status_index
A
4
B
6

Related

MySQL - Comparing two dates in the WHERE clause

I have a table, links that links two categories (parent & child) together. The table has five fields:
autoinc
parent_category_name year(4) NOT NULL
parent_category_year varchar(255) NOT NULL
child_category_name year(4) NOT NULL
child_category_year varchar(255) NOT NULL
I am trying to write an INSERT SELECT that grabs both the parent & child category_id, and inserts it into a temp table.
INSERT INTO temp (parent_category_id, child_category_id)
SELECT parent.parent_category_id, child.child_category_id
FROM links
JOIN categories AS parent
ON parent.name = link.parent_category_name
AND parent.year = link.parent_category_year
JOIN categories AS child
ON child.name = link.child_category_name
AND child.year = link.child_category_year
This query works fine, but I need to apply some business rules. The rules are:
The parent year must be the same as the child year
OR
The parent year must be one year less than the child year
I've added a WHERE clause to my query:
WHERE link.child_category_year = link.parent_category_year
OR link.child_category_year - link.parent_category_year = 1
When this INSERT statement executes in my Perl code, I get the following exception:
DBI Exception: DBD::mysql::db do failed: BIGINT UNSIGNED value is out of range in '(`my_database`.`links`.`child_category_year` - `my_database`.`links`.`parent_category_year`)' [for Statement "
So, I take it that the INSERT does not like my date subtraction in the WHERE clause. I explored using the DATEDIFF function, but I am not simply looking for a one year difference in dates, but rather one year less on the parent than the child.
How can I accomplish this without the insert error?
OR link.child_category_year - link.parent_category_year = 1 may produce negative substraction result. Of course negative value cannot be stored as UNSIGNED.
Simply convert your expression to
OR link.child_category_year = link.parent_category_year + 1
Totally unclear why "year" would be stored as an unsigned bigint. That is way overkill for my understanding of "year".
In any case, why not rephrase the logic to:
WHERE link.parent_category_year = link.child_category_year
link.parent_category_year = link.child_category_year + 1
In general, you should not have a problem adding 1 to an unsigned value.
This is my first time knowing that there's a YEAR datatype and after reading the official documentation I understand that:
MySQL displays YEAR values in YYYY format, with a range of 1901 to 2155, and 0000.
Although, it doesn't specifically said that the type is UNSIGNED but the last line in the documentation says:
If strict SQL mode is not enabled, MySQL converts invalid YEAR values to 0000. In strict SQL mode, attempting to insert an invalid YEAR value produces an error.
That means you received the error because one (or more) of the subtracted value in the condition of OR link.child_category_year - link.parent_category_year = 1 is returning negative.
Now, there are a few options you could try:
You can use CAST function and change the year data as SIGNED like :
WHERE link.child_category_year = link.parent_category_year
OR CAST(link.child_category_year AS SIGNED) - CAST(link.parent_category_year AS SIGNED) = 1
Or you can set NO_UNSIGNED_SUBTRACTION sql_mode and run the query as is:
SET sql_mode='NO_UNSIGNED_SUBTRACTION'
You can also consider changing the YEAR datatype to INTEGER and run the query as is:
ALTER TABLE links
MODIFY parent_category_year INT NOT NULL,
MODIFY child_category_year INT NOT NULL;

MySQL Query where id = id_product error

i'm working with mysql in a nodejs web app. I don't understand why when I ask for some id (key) it gives me more than 1 result.
When I:
SELECT * FROM products WHERE id = 1;
This happens, I get 3 results, but I only want 1:
1, 001 and 0000001.
I just want the info of one product (id: 1 in this example)
How can I fix this?
ID type is varchar(20)
If I use LIKE instead of = my result changes:
SELECT * FROM products WHERE id LIKE 0000001;
I get the info of id = 1 instead 0000001. Don't know why.
Thanks
The WHERE clause of your query contains a comparison of a literal numeric value with a string (column id).
When it needs to compare values of different type, MySQL uses several rules to convert one or both of the values to a common type.
Some of the type conversion rules are not intuitive. The last rule is the only one that matches a comparison of an integer number with a string:
In all other cases, the arguments are compared as floating-point (real) numbers.
When they are converted to floating-point (real) numbers, 1 (integer), '1', '0001' and '0000001' are all equal.
In order to get an exact match the literal value you put in the query must have the same type as the column id (i.e string). The query should be:
SELECT * FROM products WHERE id = '1'
The problem is that you are looking by a varchar type using an integer cast.
Try to add quotes to the id parameter:
SELECT * FROM products WHERE id = '1';
If you want to add integer ids with with leading zeros, I recommend you to use the zerofill option:
https://dev.mysql.com/doc/refman/5.5/en/numeric-type-attributes.html
If you want to use use alphanumeric values then keeps the ID type as varchar, but remember to enclose the search param into quotes.
Numbers in MySQL (and the real world) don't have leading zeros. Strings do.
So, you just need to make the comparison using the right type:
SELECT *
FROM products
WHERE id = '1';
What happens with your original query is that the id is converted to a number. And '1', '001' and '0000001' are all converted to the same integer -- 1. Hence, all three pass the filter.

How to get String value from a boolean value using MySQL query in Jasper Studio

I have an SQL query to get results from my database table. When I run this query in Jasper Studio it should bring me following.
Nocte & Mane are boolean type colomns in the table. If the Nocte column is true then, it could show as a string ("Nocte") and this should same for the mane.
SQL Query
select * from medication where $X{IN,idmedication,list} order by `LastUpdated` desc
This is the query I am using in Jasper report and idmedication and list are parameters. LastUpdated is a timestamp. This list includes Integer values, which are the idMedications.
Have any ideas to do above task in Jasper Studio?
I can think of two approaches at the moment:
Use expressions when you design the report, it could be something like ($F{Nocte}?"Nocte":"something else")
Modify the query so that it returns varchar instead of boolean. For example:
select case when Nocte = 1 then "Nocte" else "something else" end Nocte
from your_table ...
the solution is something like bellow
(
${your_filed_name}==true?"Nocte"":"mane"
)
Hope this answer your question. And you can chain the condition or get into more complex expression.

MySQL automatic string to integer casting in where clause?

I am not new to MySQL but a strange situation happened in my code today coincidently which got me surprised. Can someone explain why this gives me identical results?
SELECT * FROM `products` WHERE id = 12
and
SELECT * FROM `products` WHERE id = '12ABC'
In both cases I get the same result with the same record being selected. I would expect that second one would return me nothing?! My ID field is int(11) unsigned with auto_increment flag turned on.
From MySQL docs:
When an operator is used with operands of different types, type conversion occurs to make the operands compatible
Documentation
So basically, '12ABC' is cast to 12.
MySQL has to make a conversion to make a compare betwen 2 different types. It tries to make the string to an int and get the digits from the string starting from the beginning.
It you had for instance
'ABC12'
the result of the string conversion to int would be 0

Is OK to enclosing all values in SQL statement with single quotes?

Is it ok to enclose all values in SQL statement with single quotes ? For example:
This is simple table called books:
id | title
1 | Some book name
2 | Second book name
Is it OK to write statement like this:
SELECT * FROM books WHERE id = '1'
I've tested that query in SQL server 2008 and MySQL 5 and it works good, but I am curious is there any performance issue, because ID field is acctualy integer.
And second question is it OK to write statement like this:
SELECT * FROM books WHERE id = N'1'
N prefix is used in SQL server for UTF-8 fields, but I've tested that in SQL server and MySQL and both worked OK. I don't know if SQLite support N prefix, because I didn't test that.
The reason why I am asking this is because I am building database class that will work with popular SQL databases (SQL Server, MySQL, SQLite and maybe MS Access), so when performing selecting, inserting or updating data I don't have to worry about field datatype. I can always enclose value with N'Some value', but I am curious is this correct and is there any performance issues?
In SQL Server, you can get an implicit conversion when doing this. Sometimes it won't affect the plan or have noticeable impacts on performance, but sometimes it might. They are generally deemed to be bad. Inspect the plans for these two queries against AdventureWorks2012:
SELECT * FROM Sales.SalesOrderHeader WHERE SalesOrderID = 43659;
SELECT * FROM Sales.SalesOrderHeader WHERE SalesOrderID = '43659';
The latter contains a CONVERT_IMPLICIT (hover over the tooltip for the CI seek).
You also want to be very careful about switching between VARCHAR and NVARCHAR - in some cases this can be dreadful for performance, depending on the underlying data type and whether the literal has the N prefix.
Long story short: don't do this. Write your ORM thingy so that it understands the different data types and handles them appropriately.
SELECT ... WHERE int_type = '123' is fine to do. SQL will convert '123' to an integer once and be done with it.
However, SELECT ... WHERE char_type = 123 is no okay, because SQL will have to convert every cell into an integer. See that char_type = '0123' and char_type = '00123' will also match. So it has to do more work.
Thanks to #MartinSmith for pointing out a resource for precedence in casting: http://msdn.microsoft.com/en-us/library/ms190309.aspx
Here's an example bug in MySQL that says the implicit typecast from quoted string of digits to an integer causes a severe performance issue: http://bugs.mysql.com/bug.php?id=43319
It's best to not quote numbers.
SQL Server and MySQL both perform implicit type conversions, but it doesn't make it a good practice; use the appropriate native type when you can. This will let you avoid trying to spot the difference between:
SELECT * FROM books WHERE id = '1'
and
SELECT * FROM books WHERE id = 'l'
and
SELECT * FROM books WHERE id = 'O'
and
SELECT * FROM books WHERE id = '0'
(that's a one, a lower case L, a capital 'o', and a zero respectively)