Can't create table in laravel "General error: 1 table has more than one primary key" - sql

When using the following command php artisan migrate it returns the following error:
General error: 1 table - has more than one primary key
I have tried forcing primary key using
$table->primary('id');
Note: the ID being referenced in the other table is also of data type bigIncrements
Schema::create('stuff', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('class');
$table->timestamps();
$table->bigIncrements('owner');
$table->float('price');
$table->bigIncrements('teacher');
$table->foreign('owner')->references('id')->on('othertable');
$table->foreign('teacher')->references('id')->on('othertable');
});
}

You should make owner and teacher bigInteger instead
Schema::create('stuff', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('class');
$table->timestamps();
$table->bigInteger('owner')->unsigned();
$table->float('price');
$table->bigInteger('teacher')->unsigned();
$table->foreign('owner')->references('id')->on('othertable');
$table->foreign('teacher')->references('id')->on('othertable');
});
}

you use bigIncrements instead of integer
bigIncrements create primary key
if owners and teachers tables has bigIncrements id column so replace migration codes with:
Schema::create('stuff', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('class');
$table->timestamps();
$table->unsignedBigInteger('owner');
$table->float('price');
$table->unsignedBigInteger('teacher');
$table->foreign('owner')->references('id')->on('othertable');
$table->foreign('teacher')->references('id')->on('othertable');
});
}

Obviously bigIncrements datatype in Laravel is going to make that field primary key. In this case, you are having three primary keys which are Id, Owner and Teacher Fields.
To remove the last two from being primary keys add the following code in your migration file.
Schema::table('stuff', function (Blueprint $table) {
$table->dropPrimary('owner');
$table->dropPrimary('teacher');
});
Also, If these two fields (owner, teacher) are reference fields, I guess you don't need to give them a datatype of bigIncrements. Changing them to unsignedBigInteger can be a better choice.

Related

foreign keys and databases (laravel 6 from scratch episdoe 30)

Hi I need help with my learning I do the following code I that I am writing from laracast for some reason dont oupout foreign key value in my database Please help:
public function up()
{
Schema::create('articles', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedBigInteger('user_id');
$table->string('title');
$table->text('excerpt');
$table->text('body');
$table->timestamps();
$table->foreign('user_id')
->references('id')
->on('users')
->onDelete('cascade');
});
}
Thank you for your help
Thanks done abit more digging and got suggestion on laracast website so if some one stuck try to do the following changes:
in your laravel /config/database.php file change the following:
'engine' => null,
//Change the null to InnoDB as bellow:
'engine' => InnoDB,

Illuminate\Database\QueryException in Laravel 6.0 but not in 5.8

I am having a problem with Laravel 6.0. The same source code is running ok with Laravel 5.8. The error is the following:
Illuminate\Database\QueryException
SQLSTATE[22018]: [Microsoft][ODBC Driver 13 for SQL Server][SQL Server]Conversion failed when converting the nvarchar value 'XXXX' to data type int. (SQL: select * from [business_units] where [business_units].[code] in (0, 0, 0, 0))
Tried to create laravel project both using 5.8 and 6.0 containing the same source code but result is the same, running good in 5.8 but not in 6.0. Probably there is something wrong in Eloquent.
Here is the migration:
Schema::create('cost_centers', function (Blueprint $table) {
$table->string('code', 6)->primary();
$table->string('descr', 50);
$table->string('business_unit_code', 6)->index();
$table->foreign('business_unit_code')->references('code')->on('business_units');
$table->timestamps();
});
My Model script is:
class CostCenter extends Model
{
protected $primaryKey = 'code';
protected $fillable = ['code', 'descr', 'business_unit_code'];
public $incrementing = false;
public function businessUnit()
{
return $this->belongsTo(BusinessUnit::class);
}
}
This is after opening a form with the column in the table referencing another column where primary key is String. Did anybody encounter this problem, what is your resolution?
In the table model "business_units", I change the declaration from
This is necessary when using string as primary key.
public $incrementing = false;
to
protected $keyType = 'string';
This is specify in the Laravel upgrade guide as pointed to me by Sinnbeck of Laracast but somehow missed it.
https://laravel.com/docs/6.x/upgrade#eloquent-primary-key-type

Multiple primary keys with one auto increment laravel

I have to migrate this database with Laravel to MySQL, but it seems that I can't use multiple primary key for autoincrements elements.
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->bigIncrements('user_id');
$table->string('name');
$table->string('surname');
$table->string('email')->unique();
$table->string('tel');
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
Schema::create('collections', function (Blueprint $table) {
$table->unsignedBigInteger('user_id');
$table->foreign('user_id')->references('user_id')->on('users');
$table->bigIncrements('collection_id');
$table->primary(['user_id', 'collection_id']);
$table->string('title');
$table->string('img_url');
$table->timestamps();
});
Schema::table('collections', function (Blueprint $table) {
$table->dropPrimary('collections_collection_id_fk_primary');
});
Schema::create('contents', function (Blueprint $table) {
$table->unsignedBigInteger('collection_id');
$table->foreign('collection_id')->references('collection_id')->on('collections');
$table->bigIncrements('content_id');
$table->primary(['content_id', 'collection_id']);
$table->string('title');
$table->string('author');
$table->string('publisher');
$table->string('pages');
$table->string('google_id');
$table->string('img_url');
$table->timestamps();
});
Schema::table('collections', function (Blueprint $table){
$table->dropPrimary('contents_content_id_fk_primary');
});
}
I've tried to use dropPrimary but it doesn't execute the query, because it stops at the error: " Illuminate\Database\QueryException : SQLSTATE[42000]: Syntax error or access violation: 1068 Multiple primary key defined (SQL: alter table collections add primary key collections_user_id_collection_id_primary(user_id, collection_id))"
Can you help me?
TLDR:
The following column definition already automatically creates a primary key:
$table->bigIncrements('collection_id');
Therefore your explicit call to $table->primary() tries to create a second primary key.
Long answer
I've encountered a similar problem. I had a composite primary key on two columns which caused problems when I started to queue jobs because the framework serialized only the $primaryKey of the model (you can't define two columns as $primaryKey in models. So I added an auto increment primary column to the migration:
$this->bigIncrements('id')->primary();
This caused the error message which you are getting. After removing the primary() call it worked and I noticed that the primary key got automatically set.
Instead I am now using a composite unique key:
$table->unique(['column_a', 'column_b']);
I hope this helps in your case.

How to migrate from string column to foreign key pointing to row in other table with same string value in Laravel?

I am using Laravel 5.6 and need some help migrating a column from a populated table preserving the content logic. There is a table pages with a column named icon that accepts string values.
Ex:
Schema::create('pages', function (Blueprint $table) {
$table->increments('id');
...
$table->string('icon')->nullable();
}
The pages table is populated and the icon column, being nullable, is not always used.
A new icons table was created to store all the usable icon classes.
Ex:
Schema::create('icons', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
});
How can i migrate the icon column from the pages table to be a foreign key that points to the icons table row that has the same value in the name column or null if not populated?
I'd suggest a polymorphic many-to-many approach here so that icons are reusable and don't require a bunch of pivot tables, should you want icons on something other than a page.
Schema::create('icons', function(Blueprint $table) {
$table->increments('id');
$table->string('name');
});
Schema::create('iconables', function(Blueprint $table) {
$table->integer('icon_id');
$table->integer('iconables_id');
$table->integer('iconables_type');
});
Now you just need to determine if the pages have an existing Icon. If they do, then hold reference to them so you can insert them:
$pagesWithIcons = Page::whereNotNull('icon')->get();
At this point you need to define the polymorphic relations in your models:
// icon
class Icon extends Model
{
public function pages()
{
return $this->morphedByMany(Page::class, 'iconable');
}
}
// page
class Page extends Model
{
public function pages()
{
return $this->morphToMany(Icon::class, 'iconable');
}
}
Now you just need to create the icons (back in our migration), and then attach them if they exist:
$pagesWithIcons->each(function(Page $page) {
$icon = Icon::firstOrNew([
'name' => $page->icon
});
$icon->pages()->attach($page);
});
The above is creating an Icon if it doesn't exist, or querying for it if it does. Then it's attaching the page to that icon. As polymorphic many-to-many relationships just use belongsToMany() methods under the hood, you have all of the available operations at your leisure if this doesn't suite your needs.
Finally, drop your icons column from pages, you don't need it.
Schema::table('pages', function(Blueprint $table) {
$table->dropColumn('icon');
});
And if you need to backfill support for only an individual icon (as the many-to-many will now return an array relationship), you may add the following to your page model:
public function icon()
{
return $this->icons()->first();
}
Apologies if typos, I did this on my phone so there may be some mistakes.

Create tables and fill them with my own data after migration - Laravel

I have a few tables in a database that need specific data. I know I can always save the SQL command and execute them but I wonder if Laravel has some sort of specific command.
You can use seeders for test data, like #Alexey says. If you need the data to persist in all environments (e.g. local and production), you can insert the data after creating the table, with the Query Builder.
e.g.
<?php
class CreatePostsTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('posts', function (Blueprint $table) {
$table->increments('id');
$table->string('title');
$table->text('body');
$table->timestamps();
});
DB::table('posts')->insert([
'title' => 'Hello, world!',
'body' => 'This post will be created after migrating.',
]);
}
Laravel uses seeder classes to fill tables with data after migrations:
You need to create and register seeders and then run this command to run migration and seed the data:
php artisan migrate --seed