I'm using the Laravel 4.2 schema builder to create some tables referencing each other, and am having some issues.
I have a simplified ERD. Note that only relevant columns are shown:
Note that I cannot modify the tblcurrencies and tbldomains tables in any way, since I am developing a module to hook into an existing system.
I am trying to achieve the following:
The extensions table contains extra information about rows in the tbldomains table
The prices table contains pricing information about a domain in a certain currency, with the additional type value (registration, renewal, transfer)
I want to use foreign keys so that I can cascade deletions.
Currently, I use the following code to create the two tables:
Capsule::schema()->create('extensions', function ($table) {
$table->engine = 'InnoDB';
$table->integer('relid', 10);
// ...
$table->primary(['relid']);
$table->foreign('relid')->references('id')->on('tbldomains')->onDelete('cascade');
});
Capsule::schema()->create('prices', function ($table) {
$table->engine = 'InnoDB';
$table->integer('relid', 10);
$table->integer('currency', 10);
$table->enum('type', ['domainregister', 'domainrenew', 'domaintransfer']);
// ...
$table->primary(['relid', 'currency', 'type']);
$table->foreign('relid')->references('relid')->on('extensions')->onDelete('cascade');
$table->foreign('currency')->references('id')->on('tblcurrencies')->onDelete('cascade');
});
The creation script for the prices table results in the following SQL query:
create table `prices` (`relid` int unsigned null auto_increment primary key, `currency` int unsigned null auto_increment primary key, `type` enum('domainregister', 'domainrenew', 'domaintransfer') not null, ...) engine = InnoDB
Which in turn results in the following error:
SQLSTATE[42000]: Syntax error or access violation: 1075 Incorrect table definition; there can be only one auto column and it must be defined as a key
I have also tried setting the primary keys as unique instead, figuring that perhaps Laravel automatically set primary integer keys as auto increment.
Furthermore, I tried setting the columns as unsigned and index, as suggested by this and this answer
How do I stop the schema builder from setting the relid and currency fields to auto increment, since they are simply foreign keys?
based on Laravel Documentation Api on the below link, only string() method can have length attribute.
Laravel Documentation Api
So to make those two column unsigned and not primary key or auto increment make the following change:
from this:
$table->integer('relid', 10);
$table->integer('currency', 10);
to this:
$table->integer('relid', false, true);
$table->integer('currency', false, true);
Because as per the documentation the integer() method syntax is:
integer(string $column, bool $autoIncrement = false, bool $unsigned = false)
And what you did is you assigned a value (10) to a boolean variable ($autoIncrement) which will always returns true on this case. For further proof of this, please refer back to the below link from php.net.
php.net Boolean
I had the same issue before, and when I start referring back Laravel documentation 90% of confusion will be cleared. Hope this helps you.
Note: you can also use unsignedInteger() method, which i think it's more explicit and easier to remember:
unsignedInteger(string $column, bool $autoIncrement = false)
So the code will be like so:
$table->unsignedInteger('relid');
$table->unsignedInteger('currency');
Related
I have a table in Postgres with DDL like this one:
CREATE TABLE robots(
robot_id INTEGER NOT NULL CONSTRAINT robot_id_pkey PRIMARY KEY,
name TEXT
);
I know I can insert a record with following SQL statement:
INSERT INTO robots (robot_id, name) VALUES (nextval('robots_seq'), 'WALL-E');
I need to make CRUD operations in Phalcon for this table. Also I want to use ORM features.
So I do:
$robot = new Robots();
$robot->setRobotId(new \Phalcon\Db\RawValue("nextval('robots_seq')"));
$robot->setName('WALL-E');
$robot->save();
And get the following exception:
Uncaught PDOException: SQLSTATE[22P02]: Invalid text representation:
7 ERROR: invalid input syntax for integer: 'nextval('robots_seq')';
Is there any way to accomplish this ?
To tell Phalcon what is name of your model sequence use function getSequenceName:
public function getSequenceName() {
return 'category_id_seq';
}
Phalcon assumes that your models with serial (auto increment) columns will have a sequence named [table_name]_[column_name]_seq.
In your case, in order to make Phalcon take care of handling auto increment columns you should have a sequence named robots_robot_id_seq instead of robots_seq for the column robot_id (which I'd call just "id", by the way).
This way you do not have to worry about setting the id when creating an object and after saving Phalcon will fill that field automatically for you:
CREATE TABLE robots(
robot_id SERIAL PRIMARY KEY NOT NULL,
name TEXT
);
$robot = new Robots();
$robot->setName('WALL-E');
$robot->save();
$robot->getRobotId(); // Should return last "nextval()" sequence
Hope it helps.
Here's my migration schema:
public function up()
{
Schema::create('objects', function (Blueprint $table) {
$table->increments('id');
$table->timestamp('timestamp1');
$table->timestamp('timestamp2');
});
}
But when I execute php artisan migrate, I get this error:
Illuminate\Database\QueryException : SQLSTATE[42000]: Syntax error or access violation: 1067 Invalid default value for 'timestamp2' (SQL: create table objects (id int unsigned not null auto_increment primary key, timestamp1 timestamp not null, timestamp2 timestamp not null) default character set utf8mb4 collate utf8mb4_unicode_ci)
I must indicate that when I remove one of the 2 $table->timestamp(...); lines it works, but it doesn't when there is both. And the Object.php model is empty as it can be. Did I make a mistake?
I have read this post, but even though there is no longer errors when I change timestamp(...) into dateTime(...), I only want timestamps.
Timestamps are a little special, they must either be nullable or they must have a default value. So you must choose between timestamp('timestamp1')->nullable(); or timestamp('timestamp1')->useCurrent() or a custom default value like timestamp('timestamp1')->default(DB::raw('2018-01-01 15:23')).
I found this solution on laracasts:
nullableTimestamps() are only for default fields created_at, updated_at. for custom fields use timestamp()->nullable();
You can make one of the two timestamps nullable by using
timestamp()->nullable();
using your example, you would use:
$table->timestamp('timestamp2')->nullable();
Also laravel has built in timestamps by using
$table->timestamps();
which would automatically handle updated_at and created_at timestamping for you
i used to work with laravel 5.2 now i've upgraded to 5.4
i usually use my validation to pupolate object befor sending it to database like
$validation_rules = ['title'=>'required' , 'number'=>'present|int'];
// do validation
$obj = new Object();
foreach($validation_rules as $k=>$v )
$obj->$k = $request->input($k);
now if the user doesnt send the number parameter it would be null or false in the nnumer property of my object ... in the older versions it would automaticly change to default value of that column ... for example if i have number column type as int when inserting this object the number column would be 0
but now this doesnt happen instead im getting this error
Integrity constraint violation: 1048 Column 'number' cannot be null
btw strict mode is off
pleas note i know all about nullable , i dont want to make those fields nullable thats the whole point... its about automatically converting null values to the default column type value when field is not nullable
In Laravel 5.4 the concept of ->default(0) is different than from Laravel 5.2. In 5.4, the default only works if you don't pass anything, so when you do
$obj->$k = $request->input($k);
if $request->input($k) is null, you are sort of 'inserting' null into a column that is not nullable, which causes the error.
So it seems you have to make the column nullable in the DB and do a check in your controller:
$obj->$k = $request->input($k) ? $request->input($k) : 0;
Make sure your column 'number' is nullable. If you are using Laravel migrations to create your table, you will need to add it as $table->integer('number')->nullable();
I'm running into the following error after trying to delete a bunch of records and then insert new ones:
Error: SQLSTATE[23505]: Unique violation: 7 ERROR: duplicate key value violates unique constraint "routes_pkey" DETAIL: Key (id)=(1328) already exists.
SQL Query:
INSERT INTO routes (agency_id, route_identifier, short_name, long_name, description, route_color, text_color) VALUES (:c0, :c1, :c2, :c3, :c4, :c5, :c6) RETURNING *
Here's a simplified version of the code:
$routes = TableRegistry::get('Routes');
$routes->deleteAll(['agency_id' => $agency->id]);
# Data to be updated
$patchData = [
'stops' => $stopData,
'static_data_modified' => Time::now()
];
$patchOptions = [
'associated' => ['Stops.Routes']
];
# If: The stops have already been added to the DB
# Then: Remove them from the patch data
if (isset($stopData['_ids'])) {
unset($patchData['stops']);
# Change settings for this implementation type
$patchOptions = [];
$stopCount = count($stopData['_ids']);
}
$agency = $this->Agencies->patchEntity($agency, $patchData, $patchOptions);
$this->Agencies->save($agency);
It seems like for some reason Postgres thinks I'm inserting a record with a duplicate primary key. But I can't see how that would be possible from my code.
Here's what I see at the end of the SQL Log:
DELETE FROM
routes
WHERE
agency_id = 51
BEGIN
SELECT
1 AS "existing"
FROM
agencies Agencies
WHERE
Agencies.id = 51
LIMIT
1
INSERT INTO routes (
agency_id, route_identifier, short_name,
long_name, description, route_color,
text_color
)
VALUES
(
51, '100001', '1', '', 'Kinnear - Downtown Seattle',
'', ''
) RETURNING *
ROLLBACK
Any ideas why I'm seeing this error?
I'm on CakePHP v3.1 with Postgresql 9.4
I tried to add this but it didn't change anything:
$connection = ConnectionManager::get('default');
$results = $connection->execute('SET CONSTRAINT = routes_pkey DEFERRED');
Here are similar questions I've read without finding a solution:
ERROR: duplicate key value violates unique constraint in postgres
cakephp duplicate key value violates unique constraint
Error: duplicate key value violates unique constraint
ERROR: duplicate key value violates unique constraint "xak1fact_dim_relationship"
postgresql: error duplicate key value violates unique constraint
https://stackoverflow.com/questions/33416321/postgresql-bdr-error-duplicate-key-value-violates-unique-constraint-bdr-node
UPDATE
Following muistooshort's comment, I deleted all records from the routes table and re-ran the code and it worked fine. It also worked fine when I ran it a second time after that. So I think this supports mu's theory that something is wrong with the existing records in the db (not my code). I think the better question now is what exactly are the circumstances in the DB that are causing this and how do I fix them?
The serial type in PostgreSQL is pretty simple: it is essentially an integer column whose default value comes from a sequence. But the sequence doesn't know what you're doing to the table so things can get confused if you specify a value for the serial without using or updating the sequence.
For example:
create table t (
id serial not null primary key
);
insert into t (id) values (1);
insert into t (id) values (DEFAULT);
will produce a uniqueness violation because 1 was explicitly used for id but the sequence had no way of knowing that it was used.
Demo: http://sqlfiddle.com/#!15/17534/1
Presumably somewhere at sometime something added a row with id = 1328 without that id coming from the sequence. Or perhaps the sequence used for your PK's default was adjusted using setval to start returning values that were already in the table.
In any case, the easiest thing to do is adjust the sequence to match the table's current content using setval:
select setval('routes_id_seq', (select max(id) from routes));
The sequence should be called routes_id_seq but if it isn't, you can use \d routes inside psql to find out what its name is.
So if we update the previous example to this:
create table t (
id serial not null primary key
);
insert into t (id) values (1);
select setval('t_id_seq', (select max(id) from t));
insert into t (id) values (DEFAULT);
then we'll get 1 and 2 in our table instead of 1 and an error.
Demo: http://sqlfiddle.com/#!15/17534/7
I'd like RedBean to create unique keys/indexes when generating the schema. The following code does- opposed to how I understand the documentation- not do this:
R::setup('sqlite:rss_loader.db3');
$bean = R::findOne(IMG);
if (!$bean->id) {
$bean = R::dispense(IMG);
$bean->setMeta("buildcommand.unique.0", array('url'));
$bean->url = 'text';
R::store($bean);
$bean->wipe();
R::freeze(); //no more schema changes!
}
What is happening in sqlite ist this:
create table img (id integer primary key autoincrement, url)
What I was expecting was this:
create table img (id integer primary key autoincrement, url text unique)
Can this be achieved without write SQL against RedBean?
What version of Redbean are you using? It looks like they updated the buildcommand in the latest version. This is what the manual says:
$bean->setMeta("buildcommand.unique" , array(array($property1, $property2)));
Plugging in what you have:
$bean->setMeta("buildcommand.unique" , array(array('url')));
If that doesn't work, you may have to read the actual code under the setMeta function and see what is actually going on.
To do this on an existing table it is sufficient to "store" an empty bean like this- no data needs to be added to the DB:
$bean = R::dispense(IMG);
$bean->setMeta("buildcommand.unique", array(array(...)));
R::store($bean);
(Word of warning, if you freeze after doing this, you're not guaranteed to have all your columns)