Laravel / MySql Unique String Based On Id? - php

I have the following migration to create my MySQL database table
public function up()
{
Schema::create('project_auth_keys', function (Blueprint $table) {
$table->increments('id');
$table->integer('project_id')->unsigned();
$table->string('key', 800);
$table->string('first_name', 80);
$table->string('last_name', 80);
$table->timestamps();
// link project id with real project id
$table->foreign('project_id')->references('id')->on('projects');
});
}
Now what I want ot accomplish is make 'key' "unique"... However I know that I can do that by simply changing
$table->string('key', 800)->unique();
But I don't want to make it unique for the whole table I want to make it unique based on project_id.
For example a entry with project_id of 1 and a entry with project_id of 2 can have the same key, however there cannot be 2 same keys in the same project_id.
Is this something I can do within MySQL or will I have to make this as a rule within my controller? I can do it in my controller not a problem, but I would rather do it in my database if possible.
EDIT
Tried adding
$table->primary(array('project_id', 'key'));
Added it right below $table->primary(array('project_id', 'key'));
However after doing this I am getting a error when trying to run the migration.

Something like this?
$table->primary(array('project_id', 'key'));
You can find the same in the documentation here.
Solution 1: Since you already have a increment column defined, it is taking the same as a default primary key.
To use a composite primary key, you can either remove that column or calculate that column differently, otherwise it would throw you a duplicate primary key exception.
Also, the limitation of the length of primary key is "767" and hence you should reduce your key length to lower than that if possible.
I just tried the following and it works:
Schema::create('test', function(Blueprint $table)
{
$table->integer('project_id')->unsigned();
$table->string('key', 100); // make sure the key length is within sql standards(767), "800" is not acceptable for primary key
$table->string('first_name', 80);
$table->string('last_name', 80);
$table->timestamps();
// Add primary
$table->primary( array( 'key', 'project_id' ) );
});
Solution 2: You can just perform the validation in controller, that gives you more flexibility I believe and have the same structure, with just id as primary key. However, I am not very confident about performance. You will have to check on that.
Hope this helps.

Related

Set non primary column as Auto Increment in Laravel

This is my migration file code
Schema::create('hierarchies', function (Blueprint $table) {
$table->integer('id');
$table->integer('hierarchy_id');
$table->timestamps();
});
I want my ID column will be auto increment without primary and hierarchy_id will be my primary key.
How to do that?
After a quick look through the Laravel Migrations manual pages I think thi sshoudl do waht you want, the thing to remember is you need to make the id column unique for it to still be allowed to be a Auto Increment.
Schema::create('hierarchies', function (Blueprint $table) {
$table->integer('id')->unique();
$table->integer('hierarchy_id')->autoIncrement();
$table->timestamps();
$table->primary('hierarchy_id');
});

Composite constraint where deleted_at is NULL

I need to make a composite constraint in Laravel, which only consider non soft-deleted rows. So if the entity was deleted, the deleted_at is not null and data_1, data_2, data_3, data_4, data_5 can be inserted again.
Best I could come up with is this (table and column names were defined in previous migrations):
public function up()
{
Schema::table('table_name', function (Blueprint $table) {
$table->unique(['data_1', 'data_2', 'data_3', 'data_4', 'data_5'])
->whereNull('deleted_at');
});
}
But it doesn't work. The constraint applies even if deleted_at is not null.
I've been looking through other post with similar issues but their solutions have different approaches non related with a migration.
Turns out that making a constraint wasn't the correct approach for the problem.
A unique index allows to make a composition of columns unique, and also admit conditions.
In raw sql statement it is:
public function up()
{
DB::statement('CREATE UNIQUE INDEX table_unique_preferredNameOfIndex ON schema.table
USING btree (data_1, data_2, data_3, data_4, data_5) WHERE (deleted_at IS NULL)');
}
Not strictly the same but it gets the job done.
If a rollback is needed, just drop the index:
public function down()
{
DB::statement('DROP INDEX schema.table_unique_preferredNameOfIndex');
}

Laravel migration show "Multiple primary key defined"

My laravel migration is like below
public function up()
{
Schema::create('account_main', function (Blueprint $table) {
$table->increments('user_sn')->primary();
$table->string('member_username', 20);
$table->string('login_password', 255);
$table->integer('login_count')->default('0')->unsigned();
});
}
When I ran "php artisan migrate", show error "1068 Multiple primary key".
Could someone help to find the problem.
You don't need the ->primary() because already ->increments('...') includes it.
It's like if in MySQL you write this:
PK INT AUTO_INCREMENT PRIMARY KEY;
PRIMARY KEY(PK)
You are declaring two times the same primary key
In Laravel Eloquent ORM the type increments will be defined as primary key automatically. So don't need to use primary() method.
If the column is integer.
$table->increments('user_sn');
If the column is string
$table->string('user_sn')->primary();
If you want any other column to be unique (instead of primary key)
$table->increments('user_sn');
$table->string('member_username', 20)->unique(); // cannot contain duplicate values

String as Primary Key in Laravel migration

I've had to change a table in my database so that the primary key isn't the standard increments.
Here's the migration,
public function up()
{
Schema::create('settings', function (Blueprint $table) {
$table->text('code', 30)->primary();
$table->timestamps();
$table->text('name');
$table->text('comment');
});
}
However, MySQL keeps returning with,
Syntax error or access violation: 1170 BLOB/TEXT column 'code' used in
key specification without a key length (SQL: alter table settings
add primary key settings_code_primary(code)
I've tried leaving the normal increments id in there and modifying the table in a different migration but the same thing happens.
Any ideas of what I'm doing wrong?
Laveral Version 5.4.23
Change it to string.
$table->string('code', 30)->primary();

Laravel Migrations self-referencing foreign key General error: 1005 Can't create table

Why do I have a problem creating a table using Laravel Migrations Schema Builder?
The problem occurs with a table with a self-referencing foreign key.
Schema::create('cb_category', function($table)
{
$table->integer('id')->primary()->unique()->unsigned();
$table->integer('domain_id')->unsigned();
$table->foreign('domain_id')->references('id')->on('cb_domain');
$table->integer('parent_id')->nullable();
$table->foreign('parent_id')->references('id')->on('cb_category')->onUpdate('cascade')->onDelete('cascade');
$table->string('name');
$table->integer('level');
});
SQLSTATE[HY000]: General error: 1005 Can't create table 'eklik2.#sql-7d4_e' (errno: 150) (SQL: alter table `cb_category` add constraint cb_category_parent_id_foreign foreign key (`parent_id`) references `cb_category` (`id`) on delete cascade on update cascade) (Bindings: array ())
[PDOException]
SQLSTATE[HY000]: General error: 1005 Can't create table 'eklik2.#sql-7d4_e' (errno: 150)
You have to break this into two Schema blocks, one creating the columns, the other adding the FKs. mysql can't do both at the same time.
Two querys work :
Schema::create('cb_category', function($table)
{
$table->integer('id')->primary()->unique()->unsigned();
$table->integer('parent_id')->nullable();
});
Schema::table('cb_category', function (Blueprint $table)
{
$table->foreign('parent_id')->references('id')->on('cb_category')->onUpdate('cascade')->onDelete('cascade');
});
I may be too late for the party, but the official docs claim that the foreign key, in case of integer, must be ->unsigned();
http://laravel.com/docs/4.2/schema#foreign-keys
Note: When creating a foreign key that references an incrementing
integer, remember to always make the foreign key column unsigned.
Also, Artisan does not fail if you (as I have) misspell unsigned() and I have spent quite a few hours trying to figure out why the key was not created.
So two things:
1. Always make the foreign key column unsigned in case of incrementing integers
2. Check the spelling of unsigned()
Also a late response but probably a more idiomatic way for Laravel 8:
use App\Models\CbCategory;
...
Schema::create("cb_category", function(Blueprint $table)
{
$table->id();
$table->foreignIdFor(CbCategory::class, "parent_id")
->constrained()
->cascadeOnUpdate()
->cascadeOnDelete()
->nullable();
});
Please Note: I guessed the class name of CbCategory here. Using the class reference firsthand (instead of the former table name string) enables your static code checkers to pick up on future class name changes.
Also the _id-suffix at the parent_id column name is important.
May the following resources quench your thirst for knowledge:
id(): https://laravel.com/docs/8.x/migrations#column-method-id
foreignIdFor(): https://laravel.com/api/8.x/Illuminate/Database/Schema/Blueprint.html
cascadeOnDelete() & cascadeOnUpdate(): https://laravel.com/api/8.x/Illuminate/Database/Schema/ForeignKeyDefinition.html
Schema::create('cb_category', function (Blueprint $table) {
$table->increments('id')->unsigned();
$table->integer('domain_id')->unsigned();
$table->foreign('domain_id')->references('id')->on('cb_domain');
$table->integer('parent_id')->nullable();
$table->foreign('parent_id')->references('id')->on('cb_category')->onUpdate('cascade')->onDelete('cascade');
$table->string('name');
$table->integer('level');
});
Try this
I think you have another table that references the current table that you want to create.
I had this problem and remove that table and my problem was solved
Schema::create('categories', function (Blueprint $table) {
$table->id();
$table->integer('parent_id')->unsigned();
$table->foreign('parent_id')->on('categories')->references('id');
});
i got same error when i used this code, after change "$table->integer('parent_id')->unsigned()" to "$table->bigInteger('parent_id');"
my problem solved.
The point here is to make sure that the type of foreign key is the same as the primary key.
Since Laravel 8+ you don't have to break into two Schema blocks. You can use
foreignIdFor(CbCategory::class, 'cb_category_id') and it will create a column named cb_category_id
Ex.
Schema::create("cb_category", function(Blueprint $table)
{
$table->id();
$table->foreignIdFor(CbCategory::class, 'cb_category_id')->nullable()->constrained()->cascadeOnUpdate()->cascadeOnDelete();
});
Any additional column modifiers (Ex. nulleable) must be called before the constrained method.
You can use a second parameter in foreignIdFor for the referencing column name (in case it isn't 'id') NOT for the name you want it to have, in your case the name will automatically be 'cb_category_id'

Categories