laravel set postgresql identity column in migration - laravel

laravel $table->id() will set default nextval('tablename_id_seq'::regclass)
how to set GENERATED BY DEFAULT AS IDENTITY
CREATE TABLE color (
color_id INT GENERATED BY DEFAULT AS IDENTITY,
color_name VARCHAR NOT NULL
);

To quote from the index modifiers table in the current documentation regarding migrations:
->generatedAs($expression)
Create an identity column with specified sequence options (PostgreSQL).
The following code
Schema::create('color', function (Blueprint $table) {
$table->mediumInteger('color_id')->generatedAs();
$table->string('color_name');
});
generates
create table "color" (
"color_id" integer generated by default as identity not null,
"color_name" varchar(255) not null
)
If you add ->nullable() between mediumInteger('color_id') and generatedAs(), the color_id column is instead:
"color_id" integer generated by default as identity null

Related

How can I set index for json column in mysql 8 with laravel migration

I'm creating a project with laravel 6. One of my table column type is json.
The data format in the table column is like this:{age:30, gender:male, nation:china,...}. I am wondering if there is a way for me to set index for this column with laravel migration. my database version is mysql 8.0.21.
thank you!
I found this article very helpful for figuring this out. So for your example structure above, you might have a migration that looks like the following:
public function up(){
Schema::create('my_table', function(Blueprint $table){
$table->bigIncrements('id');
$table->json('my_json_col')->nullable();
$table->timestamps();
// add stored columns with an index
// index in this is optional, but recommended if you will be filtering/sorting on these columns
$table->unsignedInteger('age')->storedAs('JSON_UNQUOTE(my_json_col->>"$.age")')->index();
$table->string('gender')->storedAs('JSON_UNQUOTE(my_json_col->>"$.gender")')->index();
$table->string('nation')->storedAs('JSON_UNQUOTE(my_json_col->>"$.nation")')->index();
});
}
And this is equivalent to the following mysql statement:
create table my_table
(
id bigint unsigned auto_increment primary key,
my_json_col json null,
created_at timestamp null,
updated_at timestamp null,
age int unsigned as (json_unquote(json_unquote(json_extract(`my_json_col`, _utf8mb4'$.age')))) stored,
gender varchar(255) as (json_unquote(json_unquote(json_extract(`my_json_col`, _utf8mb4'$.gender')))) stored,
nation varchar(255) as (json_unquote(json_unquote(json_extract(`my_json_col`, _utf8mb4'$.nation')))) stored
)
collate = utf8mb4_unicode_ci;
create index my_table_age_index
on my_table (age);
create index my_table_gender_index
on my_table (gender);
create index my_table_nation_index
on my_table (nation);
And a simple view of the table after creation:
This example created actual stored columns, which for this scenario i think is what you would want. But you can also make virtual columns, which are created at query time instead of persistent columns, and you would just use the virtualAs function instead of the storedAs function in the migration.
These functions are documented in the Column Modifiers section of the Laravel migration docs, but it doesn't go into detail on JSON columns, this requires a bit more mysql knowledge.
I also found this article helpful for the mysql side of things for the JSON columns (SemiSQL).

Migrate from increments to bigIncrements from existing table

Im been searching around in laravel issues/forums on how to migrate changes from increments() to bigIncrements() using existing tables.
Error : SQLSTATE[HY000]: General error: 1833 Cannot change column 'id': used in a foreign key constraint 'account_users_acc_id_foreign' of table 'mydatabasename.account_users' (SQL: ALTER TABLE accounts CHANGE id id BIGINT UNSIGNED AUTO_INCREMENT NOT NULL)
i know its because of the foreign table, then i tried to disabled constraint using Schema::disableForeignKeyConstraints()
Error : SQLSTATE[HY000]: General error: 1025 Error on rename of './mydatabasename/#sql-ea_201' to './mydatabasename/accounts' (errno: 150 - Foreign key constraint is incorrectly formed) (SQL: ALTER TABLE accounts CHANGE id id BIGINT UNSIGNED AUTO_INCREMENT NOT NULL)
in my up() function:
i also tried to switch the order of the loops
Error: SQLSTATE[HY000]: General error: 1832 Cannot change column 'acc_id': used in a foreign key constraint 'account_users_acc_id_foreign' (SQL: ALTER TABLE account_users CHANGE acc_id acc_id BIGINT UNSIGNED DEFAULT NULL, CHANGE app_user_id app_user_id BIGINT UNSIGNED NOT NULL, CHANGE approved_by approved_by BIGINT UNSIGNED DEFAULT NULL, CHANGE rejected_by rejected_by BIGINT UNSIGNED DEFAULT NULL)
Is there any way to solve this?
References:
DBAL doctrine : https://www.doctrine-project.org/projects/doctrine-dbal/en/2.9/reference/schema-manager.html
Could you:
Store each table's foreign keys in an array of [$table_name => $array_of_foreign_keys]
Drop all foreign keys
Change each table's id column to use bigIncrements
Change each foreign key column to be type unsigned big integer
Loop through the array from step 1, recreating all foreign keys (by looping through each foreign key by table name)
I tried to implement like #brice suggested. for now its working..
below is migration code. i dont know it is the best practice or not
this is my gist : https://gist.github.com/afiqiqmal/6518a2048246cd76c03bdee04ff87a82

Laravel migration script produces multiple primary key columns

The following migration function:
public function up()
{
Schema::create('translations', function (Blueprint $table) {
$table->increments('id');
$table->string('table_name', 32);
$table->string('column_name', 32);
$table->integer('foreign_key', 11)->unsigned();
$table->string('locale', 11);
$table->text('value');
$table->unique(['table_name', 'column_name', 'foreign_key', 'locale']);
$table->timestamps();
});
}
is producing the following SQL query:
create table `translations` (
`id` int unsigned not null auto_increment primary key,
`table_name` varchar(32) not null,
`column_name` varchar(32) not null,
`foreign_key` int unsigned not null auto_increment primary key,
`locale` varchar(11) not null,
`value` text not null,
`created_at` timestamp null,
`updated_at` timestamp null
) default character set utf8mb4 collate utf8mb4_unicode_ci engine = InnoDB ROW_FORMAT=DYNAMIC
Notice the additional auto_increment primary key on the foreign_key field. This is the problem. How do I alter the migrations script so that it does not make foreign_key a second auto_increment primary key column?
(In case this looks familiar, this is from the base code for Voyager.)
This is because the second argument of the integer() method is the step value used for the autoincrement. You can't set the length of a integer column, instead use the column type that better suits your needs.
https://laravel.com/docs/5.4/migrations#columns

Laravel Eloquent relationship with more than one join column

I'm new to laravel and try to use Eloquent.
Assuming there is the following database structure:
CREATE TABLE `a` (
`userid` int(11) NOT NULL,
`aid` int(11) NOT NULL,
`name` varchar(255) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `p` (
`userid` int(11) NOT NULL,
`pid` int(11) NOT NULL,
`aid` int(11) NOT NULL,
`text` text NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
ALTER TABLE `a` ADD PRIMARY KEY (`userid`,`aid`);
ALTER TABLE `p` ADD PRIMARY KEY (`userid`,`pid`);
Now I want a relation between the tables:
p contains a with p.userid=a.userid AND p.aid=a.aid
How can I do a relationship with more than one column?
First I want to mention that if you can't find a straight solution, there is always a workaround. The reason why you cannot do a relationship with more than one column in one table is that you need the same number of columns in the other table. So if you had 2 columns of type int in the first table, you need 2 columns of type int in the second table aswell to link them both. And as I see from what you provided, you are repeating data which suggests that your database is not normalized. I would suggest you do the following:
CREATE TABLE `a` (
`userid` int(11) NOT NULL,
`aid` int(11) NOT NULL unique,
`name` varchar(255) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `p` (
`id` int(11) NOT NULL,
`userid` int(11) NOT NULL,
`pid` int(11) NOT NULL unique,
`text` text NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
ALTER TABLE `a` ADD PRIMARY KEY (`userid`);
ALTER TABLE `p` ADD PRIMARY KEY (`id`);
ALTER TABLE `p` ADD FOREIGN KEY (`userid`) REFERENCES `a` (`userid`)
This is what I think that is more suitable for you. However to answer your question, since you are using laravel in the a model do this:
class A extends Eloquent{
public function p(){
return $this->belongsTo('App\P','userid')
// or hasMany
}
public function p(){
return $this->belongsTo('App\P','aid')
// or hasMany
}
}
and the same thing in the p model
class P extends Eloquent{
public function a(){
return $this->hasMany('App\A','userid')
//or belongsTO
}
public function a(){
return $this->hasMany('App\A','pid')
//or belongsTO
}
}
NOTE
PLEASE keep in mind that the method belongsTo or hasMany is decided by your database model, on how you defined the database.

Table creation with h2 database

I am new to h2.I just using h2 in spring embedded mode with hibernate.I am trying to execute the following scripts using h2.
CREATE TABLE acct_authority (
id bigint(20) NOT NULL auto_increment,
name varchar(255) NOT NULL default '',
value varchar(255) NOT NULL,
PRIMARY KEY (id),
UNIQUE KEY name (name)
);
The table acct_authority is created without any error.But if i create another table with the following script.
CREATE TABLE acct_role (
id bigint(20) NOT NULL auto_increment,
name varchar(255) NOT NULL default '',
PRIMARY KEY (id),
UNIQUE KEY name (name)
);
It shows error as constraint name allready exists.What mistake i did.
You tried to create two constraints with same name. As you see, both CREATE TABLE statements contain following:
UNIQUE KEY name (name)
Result is that first one creates constraint named name, and second one fails because constraint name already exists. Problem can be solved by using unique names. Also in general it makes sense have little bit more descriptive names for database objects. Maybe you can use for example something like following:
UNIQUE KEY acct_authority_name_UNIQUE (name)
...
UNIQUE KEY acct_role_name_UNIQUE (name)

Resources