Alternatively setting Null values in columns - mysql

I am building a database and one of the tables contains the columns "sensor_id" and "station_id". When someone tries to insert a new row in the table we can have a NULL value in the "sensor_id" column but then we can not have a NULL value in the "station_id" under no circumstances. Vice versa, when the "station_id" is NULL, the "sensor_id" must not be NULL. If a value is entered at both columns that is not a problem.
I am currently working in MySQL Workbench and it seems that my choices are to set both columns as NN(Not NULL) which is too strict implementation as one of them is sufficient, to set just one of them as NN which means that one specific column must always be filled(not the case either) or set none of them NN which is too loose as at least one of both values must be given.
Visually the table looks like this(sorry for the Microsoft Word substitute but I have problems with MYSQL server and can not acces the database):
Alert_id is the primary key of the table, so duplicate values are allowed for the other two columns.
How could I implement this?

You should add contstraint to this table, like that:
CONSTRAINT CheckSensorStationNotNull CHECK (station_id is not null or sensor_id is not null)

Related

MYSQL query table using column position, NOT column name

Is it possible to write a query like the one below?
UPDATE sale SET sale_order='123456789' WHERE **COLUMN_1** = 2
where I don't explicitly pass the column name? Only its position?
I could get the column names but I am trying to avoid querying the database only to get them.
Thanks.
To answer your question, no, there is no syntax in SQL to reference the column by its position. This goes back to relational theory, in the sense that a table is a set of columns, and members of a set are unordered.
You will either have to know the column name, or else query it from the database:
SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA=SCHEMA() AND TABLE_NAME='sale'
AND ORDINAL_POSITION=1;
It looks like you are trying to design a query that updates a row by primary key, by assuming the first column is the primary key. The primary key isn't necessarily the first column. It isn't necessarily an integer. It isn't necessarily a single column.
So you are already making assumptions about the table definition. You might as well assume the primary key column is named id or some other convention.

INNODB -> Should the default column be zero or null?

My english is a little weak sorry
When using INNODB, must the column be 0 or should it be null?
Does the problem occur if the joined columns are defined as 0?
Finally, which is better in terms of performance?
Thanks.
Ignore the problem. You do not have to provide a DEFAULT value. You do not have to declare a column NULL (or NOT NULL).
Instead...
Think about the application.
Case 1: Your application will always have a value for that column, and it will always specify the value. Then declaring the column to be NOT NULL and not providing a DEFAULT makes sense.
Case 2: You don't have a value yet. Example: The table has start_date and end_date. You create a row when the thing "starts", so you fill in start_date (see Case 1) but leave end_date empty. "Empty" could be encoded as NULL and DEFAULT NULL. Later you UPDATE the table to fill in the end_date with a real value.
Case 3: The table has a "counter". When you initially add a row, the counter needs to start with "1". Later you will UPDATE ... SET counter=counter+1. You could either explicitly put the "1" in when you create the row, or you could leave out the value when inserting, but have the column declared NOT NULL DEFAULT '1'
NULL could represent "not-yet-filled-in" (Case 1), "don't know the value", "use the default", and several other things. This is an application choice.
There are other uses for NULL. Unless you have a use for NULL, declare each column NOT NULL.
If, when INSERTing, you specify all the columns, then there is no need for DEFAULTs. DEFAULTs are a convenience, not a necessity. Without a DEFAULT, you get "0" for numeric NOT NULL columns, or '' for strings.
Performance -- Probably not an issue. Do you have a particular example we should discuss?
JOINing -- I would avoid joining on a column that might have NULL in it. This rarely happens in "real life", since one joins on the unique identifier for rows in one column with a column in the other table:
FROM A JOIN B ON B.id = A.b_id
That is, B.id is probably the PRIMARY KEY of B, hence cannot be NULL. On the other hand, A.b_id could be NULL to indicate there is no row in B corresponding to the row in A. No problem.

How to replace null primary keys in MySql

I have to migrate an old Paradox database to MySql. The Paradox database contains composite primary keys with null values (composite keys are composed by 3,4 or 5 fields and it could have 1 or 2 fields with a Null value). The problem is null values in pk are not allowed in MySql. It is impossible to replace the null values directly in Paradox (5 millions of lines in some tables), so how could we do ?
Thanks in advance for your solutions.
Assuming nulls in PK means they aren't needed to be unique, they could be any value, so assign an arbitrary value to nulls.
To do this, create a trigger on the MySQL table like this:
delimiter //
create trigger trig_pk_col_1 before insert on mytable
for each row
begin
set new.pk_col_1 = coalesce(new.pk_col_1, 999);
set new.pk_col_2 = coalesce(new.pk_col_2, 999);
-- etc for other
end;//
delimiter ;
I've chosen 999 as the arbitrary non-null value, but you can chose anything.
If the logic needs to be more sophisticated, you can code it as you like.
Also, I used coalesce() for brevity, but you can use the more verbose if instead if you prefer:
if new.pk_col_1 is null then
set new.pk_col_1 = 999;
end if;
-- etc
I think you have two choices in the MySQL DB,
(a) use a PK, which requires to replace null values / ignore such rows
(b) use a UNIQUE-constraint, which still allows null values, instead of a PK.
For option (a),
I'd suggest to disable the primary key constraint and import the data; then do all necessary corrections and reactivate the primary key. If you want to get rid of rows with null values in the potential PK columns, you could also make use of the IGNORE-keyword, which skips rows violating PK-constraints when inserting (cf. primary key and unique index constraints)
Option (b),
should allow to import the data as is. You can then do corrections or leave the data as is.

SQL coalesce(): what type does the combined column have?

Lets say I use coalesce() to combine two columns into one in select and subsequently a view constructed around such select.
Tables:
values_int
id INTEGER(11) PRIMARY KEY
value INTEGER(11)
values_varchar
id INTEGER(11) PRIMARY KEY
value VARCHAR(255)
vals
id INTEGER(11) PRIMARY KEY
value INTEGER(11) //foreign key to both values_int and values_varchar
The primary keys between values_int and values_varchar are unique and that allows me to do:
SELECT vals.id, coalesce(values_int.value, values_varchar.value) AS value
FROM vals
JOIN values_int ON values_int.id = vals.value
JOIN values_varchar ON values_varchar.id = vals.value
This produces nice assembled view with ID column and combined value column that contains actual values from two other tables combined into single column.
What type does this combined column have?
When turned into view and then queried with a WHERE clause using this combined "value" column, how is that actually handled type-wise? I.e. WHERE value > 10
Som rambling thoughts in the need (most likely wrong):
The reason I am asking this is that the alternative to this design have all three tables merged into one with INT values in one column and VARCHAR in the other. That would of course produce a lots of NULL values in both columns but saved me the JOINs. For some reason I do not like that solution because it would require additional type checking to choose the right column and deal with the NULL values but maybe this presented design would require the same too (if the resulting column is actually VARCHAR). I would hope that it actually passes the WHERE clause down the view to the source (so that the column does NOT have a type per se) but I am likely wrong about that.
You query should be explicit to be clear, In this case mysql is using varchar.
I would write this query like this to be clear
coalesce(values_int.value,cast(values_varchar.value as integer), 0)
or
coalesce(cast(values_int.value as varchar(20)),values_varchar.value,'0')
you should put in that last value unless you want the column to be null if both columns are null.
Returns the data type of expression with the highest data type precedence. If all expressions are nonnullable, the result is typed as nonnullable.
So in your case the type will be VARCHAR(255)
Lets say I use coalesce() to combine two columns into one
NO, that's not the use of COALESCE function. It's used for choosing a provided default value if the column value is null. So in your case, if values_int.value IS NULL then it will select the value in values_varchar.value
coalesce(values_int.value, values_varchar.value) AS value
If you want to combine the data then use concatenation operator (OR) CONCAT() function rather like
concat(values_int.value, values_varchar.value) AS value
Verify it yourself. An easy way to check in MySQL is to DESCRIBE a VIEW you create to capture your dynamic column:
mysql> CREATE VIEW v AS
-> SELECT vals.id, coalesce(values_int.value, values_varchar.value) AS value
-> FROM vals
-> JOIN values_int ON values_int.id = vals.value
-> JOIN values_varchar ON values_varchar.id = vals.value;
Query OK, 0 rows affected (0.01 sec)
Now DESCRIBE v will show you what's what. Note that under MySQL 5.1, I see the column as varbinary(255), but under 5.5 I see varchar(255).

MySQL unique index doesnt apply when values are NULL

I have a table for detecting views of articles - it should have one unique row for each article_id&&NULL&&IP when noone is logged in and unique row for each article_id&&loggedInUser&&IP. So I thought that when noone is logged in I will just add a NULL instead of user_id. But MySQL suprised me - when I've added UNIQUE KEY like article_id&&user_id&&IP it worked fine for logged in users, but if no user logged in it started to add rows like (e.g.):
article_id | user_id | IP
5 NULL 192.168.3.50
5 NULL 192.168.3.50
5 NULL 192.168.3.50
5 NULL 192.168.3.50
This doesnt seem much unique - I know it is caused by NULL but how to solve this? Should I just rely on the fact that no user will have user_id "0"?
Thanks.
This is intentional and is documented:-
http://dev.mysql.com/doc/refman/5.0/en/create-index.html
A UNIQUE index creates a constraint such that all values in the index must be distinct. An error occurs if you try to add a new row with a key value that matches an existing row. This constraint does not apply to NULL values except for the BDB storage engine. For other engines, a UNIQUE index permits multiple NULL values for columns that can contain NULL. If you specify a prefix value for a column in a UNIQUE index, the column values must be unique within the prefix.
While you could use a user id of 0 I would be concerned that you might have 0 used elsewhere when you do not want a record found. For example I often just convert any input id field to an integer and if someone has tried to hack around and enter a string this might well be converted to 0. In such a case I wouldn't really want the zero to be meaningful.
I would possibly be tempted to set up a 'none' userid to use in this situation.
Your current solution is going to grow huge very quickly and provide very little benefit. If it were me I would just rely on analytics to handle this sort of data. If you really want this it can be done very easily by adding one more field to your table for a count. When you are about to add a row to this look for one which already exists. If one does then instead of adding a new record just update the current record and increment the count instead. This will provide the exact same information in much less space.