Composite foreign key in Laravel - php

How do I write this constrain in a Laravel migration?
ALTER TABLE user_profiles
ADD CONSTRAINT app_profiles
FOREIGN KEY (profile_id, app_id)
REFERENCES profile_apps (profile_id, app_id);
I've tried this:
$table->foreign(['profile_id', 'app_id'])->references('profile_apps')->on(['profile_id', 'app_id']);
which turns into:
"ErrorException : Array to string conversion" in
C:\Users\CAM\Projects\mcr-back\vendor\laravel\framework\src\Illuminate\Database\Grammar.php:39
and the same as strings,
$table->foreign('profile_id, app_id')->references('profile_apps')->on('profile_id, app_id');
with error:
"SQLSTATE[42000]: Syntax error or access violation: 1072 Key column
'profile_id, app_id' doesn't exist in table"

You are mix up on and references methods using.
Right variant is:
$table
->foreign(['profile_id', 'app_id'])
->references(['profile_id', 'app_id'])
->on('profile_apps');

Use this methoid
NOTE: Make sure in your database > migration the profile table and app table is above this table migration
2014_06_14_23123123_create_profiles_table
2014_06_14_23123123_create_apps_table
before
2014_06_14_23123123_create_this_table
$table->foreign('profile_id')->references('id')->on('profiles')->onDelete('cascade');
$table->foreign('app_id')->references('id')->on('apps')->onDelete('cascade');

Related

Eloquent: Invalid default value with timestamps

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

Laravel schema builder primary key as foreign key

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');

Error's (PK's and FK's tried in the correct order)

( ! ) Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (mowanj1_in605.sportEvent, CONSTRAINT sportEvent_ibfk_1 FOREIGN KEY (eventID) REFERENCES event (eventID))' in /home/mowanj1/public_html/Web2/Assignment1/createAthlete.html.php on line 222
( ! ) PDOException: SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (mowanj1_in605.sportEvent, CONSTRAINT sportEvent_ibfk_1 FOREIGN KEY (eventID) REFERENCES event (eventID)) in /home/mowanj1/public_html/Web2/Assignment1/createAthlete.html.php on line 222
$createQuery = "CREATE TABLE sportEventMedal
sportEventMedalID INT NOT NULL AUTO_INCREMENT, sportEventID INT, medalID INT,
PRIMARY KEY (sportEventMedalID), FOREIGN KEY (sportEventID) REFERENCES sportEvent(sportEventID), FOREIGN KEY (medalID) REFERENCES medal(medalID)
$pdo->exec($createQuery);
while (! feof($file)) {
$temp = fgetcsv($file);
$insertQuery = "INSERT INTO sportEvent(eventID, sportID) VALUES('$temp[0]','$temp[1]')";
$pdo->exec($insertQuery);
}
fclose($file);
You should load event and sport before loading sportEvent. If you're already doing that correctly, then your csv file contains inconsistent data - rows that contain invalid eventID values. One option is to ignore those rows, you can query to see if the event exists before trying to insert or you can just ignore the error. Another option is to create an event for the missing ID and then to retry the insert into sportEvent. The easiest and worst option is to remove the foreign key constraint, that'll allow you to insert invalid data into your database and ignore the problem for now.

CakePHP: Unique violation: 7 ERROR: duplicate key value violates unique constraint

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

How can I make auto-increment columns non-auto-increment?

I am trying to create a table with this code.
public function up()
{
Schema::create('BookInfo', function (Blueprint $table) {
$table->increments('id');
$table->integer('bookId',11);
$table->string('Name',255);
$table->string('Publisher')->nullable();
$table->integer('Publishing_year',4)->nullable();
$table->integer('Price',5)->nullable();
$table->string('Language',30);
$table->timestamps();
});
}
When I tried php artisan migrate it shows me this error.
[Illuminate\Database\QueryException]
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 (SQL: create tableBookInfo(bookIdint not
null auto_increment primary key,Namevarchar(255) not null,
Publishervarchar(255) null,Publishing_yearint null
auto_increment primary key,Priceint null auto_increment primary key,
Languagevarchar(30) not null,created_attimestamp default 0
not null,updated_attimestamp default 0 not null) default character
set utf8 collate utf8_unicode_ci) and
[PDOException]
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
It seems laravel takes all the integer columns as auto-increment.What happened here actually and what will be solution?
The error says it all,
$table->integer('bookId',11);
^// this is considered as autoincrement rather than length
There is no length option for integers
See this
References on SO, this and this
$table->integer('bookId',11); is not syntactically correct in Eloquent ORM(you can't set any size limit for integers) and that is causing the error in your case.
And $table->increments('id'); automatically sets id as a primary key.
Find all necessary table building commands in Eloquent ORM here: http://laravel.com/docs/4.2/schema#adding-columns

Categories