Is there a function in MySQL to not allow the selection of a value directly after a value already selected from an ENUM data type in the database? - mysql

Is there code to not allow a value directly after a value that's already saved be inserted into the table. The field is an ENUM.
Cant find code anywhere
None available for ENUM
Timeslot ENUM('09:00','09:30','10:00')
09:00 saved already
'09:30' shouldn't be allowed to be inserted into the table
'10:00' should insert fine

There is no default function that I am aware of to do what you are wanting.
I think you will have to do some checks using the ENUM index. ENUM values are mapped to a numeric index. You can select column_name+0 on an ENUM column and that will give you the index value of the ENUM rather than the ENUM value. MySQL ENUM Doc
In your case the ENUM index would look something like this:
NULL -> NULL
0 -> ''
1 -> '9:00'
2 -> '9:30'
3 -> '10:00'
For instance, if you have 1 record with Timeslot set to '9:00' and you 'SELECT TimeSlot+0 FROM table' your result for the record will be 1. If the column value was '9:30' the index would be 2, etc.
You can find the potential index of an incoming value using something like this:
SELECT FIND_IN_SET('new_value', REPLACE(SUBSTRING(column_type,6, LENGTH(column_type) - 6), '\'', '') ) AS enum_options
FROM information_schema.columns
WHERE column_name='your_enum_column'
AND table_schema = 'your_schema';
If the result of this is equal to any of the index values (or index value +1) of any of the values already in the table, you do not want to allow this new entry. You can use the above query as a subquery inside a case statement to compare this new value's index to your previous values' indexes.
EDIT (4/2/2019):
After a couple of comments I think that the following may get you closer to what you need. I have not been able to test this query out, but it should be close.
CREATE TEMPORARY TABLE booking_conflicts AS (
SELECT MAX(
IF(
FIND_IN_SET(
(SELECT FIND_IN_SET('12:00', REPLACE(SUBSTRING(column_type,6, LENGTH(column_type) - 6), '\'', '') )
FROM information_schema.columns
WHERE column_name='your_enum_column'
AND table_name = 'booking'
AND table_schema = 'your_schema'),
CONCAT(time_slot+0, ',', time_slot+1)
) > 0,
1,
0) AS is_time_conflict
FROM booking
WHERE facility_id = 6
AND booking_date = '2020-07-04'
);
INSERT INTO bookings
(facility_id,booking_date,time_slot,member_id)
VALUES (6,'2020-07-04','12:00',2)
WHERE (SELECT is_time_conflict FROM booking_conflicts) = 0;
What this is doing is getting all used time_slots from that date for that facility and comparing them with the new time slot you are trying to use. If the new time slot's index is equal to the index of a previously used time_slot or of a previously used time_slot + 1, then the query will return 1, otherwise 0. We store that in a temp table and access the temp table from the insert.

Related

MYSQL: How to update unique random number to existing rows

It's been my first question to this website, I'm sorry if I used any wrong keywords. I have been with one problem from quite a few days.
The Problem is, I have a MYSQL table named property where I wanted to add a ref number which will be a unique 6 digit non incremental number so I alter the table to add a new column named property_ref which has default value as 1.
ALTER TABLE property ADD uniqueIdentifier INT DEFAULT (1) ;
Then I write a script to first generate a number then checking it to db if exist or not and If not exist then update the row with the random number
Here is the snippet I tried,
with cte as (
select subIdentifier, id from (
SELECT id, LPAD(FLOOR(RAND() * (999999 - 100000) + 100000), 6, 0) AS subIdentifier
FROM property as p1
WHERE "subIdentifier" NOT IN (SELECT uniqueIdentifier FROM property as p2)
) as innerTable group by subIdentifier
)
UPDATE property SET uniqueIdentifier = (
select subIdentifier from cte as c where c.id = property.id
) where property.id != ''
this query returns a set of record for almost all the rows but I have a table of entries of total 20000,
but this query fills up for ~19000 and rest of the rows are null.
here is a current output
[current result picture]
If anyone can help, I am extremely thanks for that.
Thanks
Instead of trying to randomly generate unique numbers that do not exist in the table, I would try the approach of randomly generating numbers using the ID column as a seed; as long as the ID number is unique, the new number will be unique as well. This is not technically fully "random" but it may be sufficient for your needs.
https://www.db-fiddle.com/f/iqMPDK8AmdvAoTbon1Yn6J/1
update Property set
UniqueIdentifier = round(rand(id)*1000000)
where UniqueIdentifier is null
SELECT id, round(rand(id)*1000000) as UniqueIdentifier FROM test;

MySQL how to create a custom id column formatted with date?

MySQL Current table
CREATE TABLE document_control (
id INT NOT NULL PRIMARY KEY AUTO_INCREMENT...
From the above - the id will be created in the following sequence: 1,2,3,4,5,6,7....
Intention
I need the sequence to go like so:
19-001
19-002
19-003
Explanation
19 - Todays year date format (yy)
001 - Increments by +1 when a new value is added.
Next year (2020)..
the sequence needs to be reset back to 001 but the 19 changes to 20 because of the year being 2020 :
20-001
20-002
20-003
Question
How can I create this custom ID column?
You can use something like the following using a INSERT ... SELECT:
INSERT INTO document_control
SELECT CONCAT_WS('-', RIGHT(YEAR(CURRENT_TIMESTAMP), 2), LPAD(COUNT(*) + 1, 3, 0))
FROM document_control
WHERE LEFT(id_custom, 2) = RIGHT(YEAR(CURRENT_TIMESTAMP), 2)
Note: It can be dangerous to use such a generated custom ID as identifier for specific records since the custom ID can change after changing the data (UPDATE or DELETE) of the table. So I don't recommend to use this custom ID as foreign key on other tables.
A better solution (in my opinion) would be the following:
CREATE TABLE document_control (
id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
name VARCHAR(10)
);
You are using a table with column id using auto increment (so the database organizes the ID itself) and the created_at column to store the date and time of the creation. You can use CURRENT_TIMESTAMP as default value so you don't have to provide a value on INSERT everytime. With these two columns you can get your custom ID with a simple query:
SELECT *, CONCAT_WS('-', RIGHT(YEAR(created_at), 2), LPAD(id, 3, 0)) AS custom_id
FROM document_control
You can create a VIEW to generate the custom ID in the background. In this case you don't have to build the custom ID on every SELECT yourself:
-- create the VIEW
CREATE VIEW v_document_control AS
SELECT *, CONCAT_WS('-', RIGHT(YEAR(created_at), 2), LPAD(id, 3, 0)) AS custom_id
FROM document_control
-- use the VIEW
SELECT * FROM v_document_control
In case you need a consecutive number without gaps and starting on "1" every year, you can use the above example (same columns) but with the following SELECT using ROW_NUMBER (since MySQL 8.0):
SELECT *, CONCAT_WS('-', RIGHT(YEAR(created_at), 2), LPAD(ROW_NUMBER() OVER (PARTITION BY YEAR(created_at) ORDER BY id), 3, 0)) AS custom_id
FROM document_control
demo on dbfiddle.uk
You can create a stored function which would run a selection to get the highest ID value, the equivalent of
select max(id) from document_control
The function would check whether the year is the current one and if so, it would use it as the first part and concatenate the incremented second part. If the document represented the last year, then you can use current year and concatenate -001 to it. And then you can call it from a before insert trigger.
However, it is not advisable to work like this, because you violate NF1. It makes much more sense to have a numeric id, a year column, a number column and a stored function which would calculate this concatenation. You can of course index the underlying columns for perfromance's sake.

get 0 when emptyornull values else max(id) when column datatype is numeric in sql server

Hi I have one doubt in sql server
get 0 when emptyornull values else max(id) when column datatype i is numeric in sql server
Table : empid
CREATE TABLE [dbo].[empid](
[id] [numeric](11, 0) NULL
) ON [PRIMARY]
GO
INSERT [dbo].[empid] ([id]) VALUES (NULL)
GO
INSERT [dbo].[empid] ([id]) VALUES (CAST(6 AS Numeric(11, 0)))
GO
based on above data I want output like below
id
6
I tried like below
select case when isnull( max(id),'')='' then cast (0 as numeric) else max(id end test from )
[Test].[dbo].[empid]
but above query is getting error
Msg 8114, Level 16, State 5, Line 9
Error converting data type varchar to numeric.
suppose no records in table then maxid will get 0
please tell me how to write a query to achive this task in sql server
You should use the COALESCE function that gives you the ability to replace a potential NULL with whatever you wish (0 in your current case) as so:
select coalesce(id, 0) as id from [dbo].[empid];
Why use ''? Just use 0:
SELECT ISNULL(id,0) AS test
FROM dbo.empid;
ISNULL returns the datatype of the first parameter, and with the SQL you had, you were therefore implicitly trying to convert '' to a numeric, which was failing.
The better way to do this is to use COALESCE function provided by SQL
COALESCE(arg1, arg2[, argN])
what it does is it takes N arguments
arg1 is a column that can be null
arg2 is a column that can be null
argN is the value that you want to replace it with
Query could be
SELECT COALESCE(Id, 0) as Id FROM [dbo].[empid]

Adapt result of one row to other rows

How can I can write the query this way, that the result of the CASE WHEN - statement is adapted to every row. So that in every row the result will be 5. Thank you very much!
CREATE TABLE DATA
(`Person` CHAR(4),
`Apples` INT(1),
`Tomatoes` INT(1),
`Result` INT(1)
);
INSERT INTO DATA
(Person, Apples, Tomatoes)
VALUES ('Mark' , 1, 2),
('Sepp', 2, 3),
('Carl', 3, 1);
UPDATE DATA
SET `Result` = CASE WHEN (`Person` = 'Sepp') THEN (`Apples` + `Tomatoes`) END;
Table of result as it should be
SQL fiddle demonstration
If you want all rows to get the value from Sepps row you can do it using a subquery.
The "normal" way would be to do this:
UPDATE DATA
SET Result = (SELECT Apples + Tomatoes FROM DATA WHERE Person = 'Sepp')
But this will most likely give you an error with MySQL (can't specify target table for update) and a workaround is to introduce another level in the query which forces a temporary table to be used, like this:
UPDATE DATA
SET Result = (
SELECT Value FROM (
SELECT Apples + Tomatoes AS Value
FROM DATA WHERE Person = 'Sepp'
) t
);

ISSUE: Mysql converting Enum to Int

I have a very simple rating system in my database where each rating is stored as an enum('1','-1'). To calculate the total I tried using this statement:
SELECT SUM(CONVERT(rating, SIGNED)) as value from table WHERE _id = 1
This works fine for the positive 1 but for some reason the -1 are parsed out to 2's.
Can anyone help or offer incite?
Or should I give up and just change the column to a SIGNED INT(1)?
this is what you want
select enum+0 as enum
This conversion to int in MySQL for enum is only possible:
CAST(CAST(`rating` AS CHAR) AS SIGNED) as value from table WHERE _id = 1
Yes, I'd suggest to change the type of the column. The issue becomes clear when you read the doc about enum type (which strongly recommends not to use numbers as enumeration values!) - the index of the enum item is returned, not the enum value itself.
Ok guys,
Just had a bit of a mere of a time with this one. I learned that i shouldn't use ENUMs where integers are the values. However We had years worth of data and i couldn't alter the database.
This bad boy worked (turning it into a character, then into a signed int).
CAST(CAST(`rating` AS CHAR) AS SIGNED) as value from table WHERE _id = 1
use
SELECT SUM( IF( columnname >0, CAST( columnname AS CHAR ) , NULL ) ) AS vals
FROM `tableName`
I wouldn't use enum here too, but it is still possible in this case to get what is needed
Creating table:
CREATE TABLE test (
_id INT PRIMARY KEY,
rating ENUM('1', '-1')
);
Filling table:
INSERT INTO test VALUES(1, "1"), (2, "1"), (3, "-1"), (4, "-1"), (5, "-1");
Performing math operations on enums converts them to indexes, so it is possible just to scale the result value:
SELECT
SUM(3 - rating * 2)
FROM
test;
Result: -1 which is true for the test case.