Can't create nodes after DB-Import (Duplicate Entries) - drupal

i exported a bunch of tables and prefixed them with "ch_" and imported them again. All using phpmyadmin. It all works fine… until I want to create something. It fails with this message:
user warning: Duplicate entry '4-4' for key 'PRIMARY' query: INSERT INTO ch_node (nid, vid, title, type, uid, status, created, changed, comment, promote, sticky) VALUES (4, 4, 'Nützliche Dokumente', 'page', 1, 1, 1288790996, 1288791130, 0, 0, 0) in /var/www/clients/client20/site60/docroot/includes/database.mysql.inc on line 172.
Whereas the '4-4' increments each time i try to save. That made me think the auto_increment value in the DB is somehow wrong - though it was correctly specified in my export.sql. Hence I tried to reset the auto_increment value to some ridiculous high number using ALTER TABLE some_table AUTO_INCREMENT=10000. Still same behaviour…
Anyone an idea what's going on here?
I did this procedure a few times before … but without this happening. It's driving me nuts :/

So, your import works fine, it's only when you try to insert a new record after everything has been imported that you get this error? If that's the case, then either:
Your auto_increment isn't set correctly.
You are specifying a value for your auto_increment field.
From the post above, it looks like you're specifying a value for your auto_increment field. You should update your auto_increment to the MAX+1 of your table, and then when you do you're insert, don't specify a value for that field and MySQL will use the auto_increment for you...

Lesson learned:
Drupal does not use MySQL's auto_increment value.
As I learned auto increment is not part of the SQL Ansi standard - it's just a very common thing. Drupal does not want to rely on some implementations of different RDBMS, so they have a table {sequences} that has a column for the table name and the next id-value that can be loaded with db_next_id($name). Of course by prefixing the table names, I had to add the prefix in the sequences table as well.
As much as it drove me nuts in the first place, I think it's a wise decision the drupal-developers made.

Related

How can I solve MariaBD auto increment key problem

I am new to MariaDB and I have an issue which seems to be easy at first side. I have a table with auto_increment id key, in which I insert some data from my app. Everything was working fine until I decided to delete all the records from the table. Now, it does not insert anything from my app. The only way to insert in it is to make it by hand and it starts from id = 1. Do you think that this is something normal for MariaDB?
Here is the code, which insert in the table:
$logs=array(
'customer_id'=>(integer)$token['customer_id'],
'driver_id'=>(integer)$driver_id,
'latitude'=>$this->data['lat'],
'longitude'=>$this->data['lng'],
'altitude'=>isset($this->data['altitude'])?$this->data['altitude']:'',
'accuracy'=>isset($this->data['accuracy'])?$this->data['accuracy']:'',
'altitudeAccuracy'=>isset($this->data['altitudeAccuracy'])?$this->data['altitudeAccuracy']:'',
'heading'=>isset($this->data['heading'])?$this->data['heading']:'',
'speed'=>isset($this->data['speed'])?$this->data['speed']:'',
'track_type'=>isset($this->data['track_type'])?$this->data['track_type']:'',
'date_created'=>AdminFunctions::dateNow(),
'ip_address'=>$_SERVER['REMOTE_ADDR'],
'date_log'=>date("Y-m-d")
);
Yii::app()->db->createCommand()->insert("{{driver_track_location}}",$logs);
I also attach an image of the structure of table driver_track_location:

Correct usage of the SQLite ON CONFLICT clause

I have a SQLite database which, amongst other things, has the following table.
CREATE TABLE IF NOT EXISTS biases
(
data INTEGER NOT NULL,
link INTEGER DEFAULT 0,
bias_type INTEGER,
ignores INTEGER DEFAULT 0,
desists INTEGER DEFAULT 0,
encashes INTEGER DEFAULT 0,
accesses INTEGER DEFAULT 0,
scraps INTEGER DEFAULT 0,
CONSTRAINT pk_bias_mix PRIMARY KEY(data,link,bias_type)
);
The constraint pk_bias_mix is being used to ensure that no two rows can have the same values for all three columns data, link and bias_type columns. So suppose I do
INSERT INTO biases (data,link,bias_type,ignores) VALUES(1,1,1,1);
things work as expected - a new row is inserted in the table. If I issue the same INSERT again I get the error
UNIQUE CONSTRAINT FAILED: biases.data,biases.link,biases.bias_type
just as expected. I tried to use the SQLite ON CONFLICT clause thus
INSERT INTO biases (data,link,bias_type,ignores) VALUES(1,1,1,1)
ON CONFLICT(data,link,bias_type) DO UPDATE SET ignores = ignores + 1;
and it worked as I had hoped - instead of adding a new row or throwing up an error SQLite incremented the value of the ignores column in the row with the matching data, link and bias_type values.
However, this is just the result of an experiment. It is not immediately clear to me from the SQLite docs that this is indeed how ON CONFLICT is supposed to behave - i.e it can be given two or more conflict constraints to be checked. What I mean by two or more constraints is specifying multiple, comma separated, columns inside CONFLICT(...) as I have done in the example above.
I suspect that this is the right usage since I am merely specifying a CONFLICT condition that replicates my indicated CONSTRAINT. However, I cannot see this explained explicitly anywhere in the docs. I'd be much obliged to anyone who might be able to confirm this.
From UPSERT:
UPSERT is a special syntax addition to INSERT that causes the INSERT
to behave as an UPDATE or a no-op if the INSERT would violate a
uniqueness constraint.
and:
The special UPSERT processing happens only for uniqueness constraint
on the table that is receiving the INSERT.
So the DO UPDATE part is not triggered by any constraint conflict but only by a unique constraint violation.
Also:
The syntax that occurs in between the "ON CONFLICT" and "DO" keywords
is called the "conflict target". The conflict target specifies a
specific uniqueness constraint that will trigger the upsert.
So it is not possible to have two or more conflict constraints to be checked in one statement.
However you can use separate UPSERT statements to check for 2 different unique constraint violations.
See a simplified demo where I added 1 more UNIQUE constraint to your table:
CONSTRAINT con_scraps UNIQUE(scraps)

Tying table records together in SQLite3

I am currently working on a database structure in SQLite Studio (not sure whether that's in itself important, but might as well mention), and error messages are making me wonder whether I'm just going at it the wrong way or there's some subtlety I'm missing.
Assume two tables, people-basics (person-ID, person-NAME, person-GENDER) and people-stats (person-ID, person-NAME, person-SIZE). What I'm looking into achieving is "Every record in people-basics corresponds to a single record in people-stats.", ideally with the added property that person-ID and person-NAME in people-stats reflect the associated person-ID and person-NAME in people-basics.
I've been assuming up to now that one would achieve this with Foreign Keys, but I've also been unable to get this to work.
When I add a person in people-basics, it works fine, but then when I go over to people-stats no corresponding record exists and if I try to create one and fill the Foreign Key column with corresponding data, I get this message: "Cannot edit this cell. Details: Error while executing SQL query on database 'People': no such column: people-basics.person" (I think the message is truncated).
The DDL I currently have for my tables (auto-generated by SQLite Studio based on my GUI operations):
CREATE TABLE [people-basics] (
[person-ID] INTEGER PRIMARY KEY AUTOINCREMENT
UNIQUE
NOT NULL,
[person-NAME] TEXT UNIQUE
NOT NULL,
[person-GENDER] TEXT
);
CREATE TABLE [people-stats] (
[person-NAME] TEXT REFERENCES [people-basics] ([person-NAME]),
[person-SIZE] NUMERIC
);
(I've removed the person-ID column from people-stats for now as it seemed like I should only have one foreign key at a time, not sure whether that's true.)
Alright, that was a little silly.
The entire problem was solved by removing hyphens from table names and column names. (So: charBasics instead of char-basics, etc.)
Ah well.

Alternative to using subquery inside CHECK constraint?

I am trying to build a simple hotel room check-in database as a learning exercise.
CREATE TABLE HotelReservations
(
roomNum INTEGER NOT NULL,
arrival DATE NOT NULL,
departure DATE NOT NULL,
guestName CHAR(30) NOT NULL,
CONSTRAINT timeTraveler CHECK (arrival < departure) /* stops time travelers*/
/* CONSTRAINT multipleReservations CHECK (my question is about this) */
PRIMARY KEY (roomNum, arrival)
);
I am having trouble specifying a constraint that doesn't allow inserting a new reservation for a room that has not yet been vacated. For example (below), guest 'B' checks into room 123 before 'A' checks out.
INSERT INTO HotelStays(roomNum, arrival, departure, guestName)
VALUES
(123, date("2017-02-02"), date("2017-02-06"), 'A'),
(123, date("2017-02-04"), date("2017-02-08"), 'B');
This shouldn't be allowed but I am unsure how to write this constraint. My first attempt was to write a subquery in check, but I had trouble figuring out the proper subquery because I don't know how to access the 'roomNum' value of a new insert to perform the subquery with. I then also figured out that most SQL systems don't even allow subquerying inside of check.
So how am I supposed to write this constraint? I read some about triggers which seem like it might solve this problem, but is that really the only way to do it? Or am I just dense and missing an obvious way to write the constraint?
The documentation indeed says:
The expression of a CHECK constraint may not contain a subquery.
While it would be possible to create a user-defined function that goes back to the database and queries the table, the only reasonable way to implement this constraint is with a trigger.
There is a special mechanism to access the new row inside the trigger:
Both the WHEN clause and the trigger actions may access elements of the row being inserted, deleted or updated using references of the form "NEW.column-name" and "OLD.column-name", where column-name is the name of a column from the table that the trigger is associated with.
CREATE TRIGGER multiple_reservations_check
BEFORE INSERT ON HotelReservations
BEGIN
SELECT RAISE(FAIL, "reservations overlap")
FROM HotelReservations
WHERE roomNum = NEW.roomNum
AND departure > NEW.arrival
AND arrival < NEW.departure;
END;

SQLite Find ROWID of most recent or next ROWID

So I have a table with data about an image. The table looks something like this...
ROWID|title|description|file_path
The file path contains the name of the image. I want to rename the image to match the ROWID.
How do I get the latest ROWID? I need to also account for rows that have been deleted as I am using this as an autoincremented primary key. Because, if a row within the table has been deleted it is possible for the table to look like this...
1|title A|description A|..\fileA.jpg
2|title B|description B|..\fileB.jpg
5|title E|description E|..\fileE.jpg
7|title G|description G|..\fileG.jpg
On top of that there could be one or more rows that have been deleted so the next ROWID could be 10 for all I know.
I also need to account for an fresh new table or a table that has had all data deleted and the next ROWID could be 1000.
In summary, I guess the real question is; Is there a way to find out what the next ROWID will be?
If you have specified AUTOINCREMENT in primary key field and table is not empty this query will return latest ROWID for table MY_TABLE:
SELECT seq
FROM sqlite_sequence
WHERE name = 'MY_TABLE'
What language? Looks like the c API has the following function:
sqlite3_int64 sqlite3_last_insert_rowid(sqlite3*);
http://www.sqlite.org/c3ref/last_insert_rowid.html
You could also just do:
select MAX(rowid) from [tablename];
Unfortunately neither of these methods completely worked the way I needed them to, but what i did end up doing was....
insert data into table with the fields I needed the rowid for filled with 'aaa'
then updated the rows with the data.
This seemed to solve my current issue. Hopefully it doesn't cause another issue down the road.
I think last_insert_rowid is what you want, usually.
Note that the rowid behavior is different depending on the autoincrement flag - either it will monotonically increase, or it will assume any free id. This will not usually affect any smaller use cases though.

Resources