Laravel 4.2 Migrations - Alter decimal precision and scale without dropping column - laravel

I wish to increase decimal precision and scale for a decimal column.
I am aware that I can drop the column, and re-create it, but doing so will mean losing the data in the column.
Is there a way using Laravel Schema::table that I can alter the precision and scale of the column without dropping it?
e.g. something like:
Schema::table('prices', function(Blueprint $t) {
$t->buy_price->decimal(5,2);
});

this worked for me:
public function up()
{
Schema::table('prices', function(Blueprint $t) {
$t->decimal('buy_price', 5, 2)->change();
});
}
when rolling back use original precision values of 3, 1 instead
public function down()
{
Schema::table('prices', function(Blueprint $t) {
$t->decimal('buy_price', 3, 1)->change();
});
}
I avoid DB specific "raw" statements as they might fail when I change to another DBMS engine. So I let Laravel handle necessary syntax when working w/DB

Just create another migration and in the up method add following code:
public function up()
{
// Change db_name and table_name
DB::select(DB::raw('ALTER TABLE `db_name`.`table_name` CHANGE COLUMN `buy_price` `buy_price` decimal(10,2) NOT NULL;'));
}
Also in the down method just set the old value so you can roll-back:
public function down()
{
// Change db_name and table_name
DB::select(DB::raw('ALTER TABLE `db_name`.`table_name` CHANGE COLUMN `buy_price` `buy_price` decimal(5,2) NOT NULL;'));
}
Then migrate as usual from the terminal/command prompt using php artisan migrate.

Didn't work for me, using select gives me a General Error: 2053 because select expects aa array to be returned. I'm not sure if it's the version of MySQL, or a windows/linux thing.
I had to use DB:statement instead:
public function up()
{
// Change db_name and table_name
DB::statement(DB::raw('ALTER TABLE `db_name`.`table_name` CHANGE COLUMN `buy_price` `buy_price` decimal(10,2) NOT NULL;'));
}
and
public function down()
{
// Change db_name and table_name
DB::statement(DB::raw('ALTER TABLE `db_name`.`table_name` CHANGE COLUMN `buy_price` `buy_price` decimal(5,2) NOT NULL;'));
}
Hope this helps anyone who comes across this.

Related

Updating the data of an existing column and copying data with migrations

Is it possible to add a new column, copy some data to this new column and update the data in another column with a Laravel migration?
I have a table something like this;
id
item
price
1
ItemOne
100.00
2
ItemTwo
200.00
Now what I need to do is,
add a new column, old_price to this table
copy the values in the price column to newly added old_price column
multiply the values in the price column with 5 and update the same column
The new table should look something like this;
id
item
price
old_price
1
ItemOne
500.00
100.00
2
ItemTwo
1000.00
200.00
Is it possible to to achieve this with a migration or a seed or something?
This change needs to be done on an application that is already in production so dropping and re-creating the tables is not an option for me here.
Also the old_price column is created just to keep a reference of the current values of the price column. It will not be updated after this and probably will be removed in an later update if everything is going right with the new prices. So I don't need to use any model events to update the column afterwards.
Any help you can give me on this is really appreciated. Thanks.
Create a new migration.
Version 1. create automatically by command:
php artisan make:migration add_price_old_to_products_table
Version 2. create manually something like this:
2021_08_18_163618_add_price_old_to_products_table.php
Manage the content by following the 3 steps in the code:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
class AddPriceOldToProductsTable extends Migration
{
public function up()
{
// 1. creating a new column
Schema::table('products', function (Blueprint $table) {
// this is just an example, you can change this
// NOTE: make sure that the type is the same as "price" column
// for avoiding type conflicts
$table->decimal('price_old', 10, 2)->nullable();
});
// 2. copying the existing column values into new one
DB::statement("UPDATE products SET price_old = price");
// 3. update the old/existing column
// CHANGE YOUR "price" COLUMN HERE...
}
public function down()
{
Schema::table('products', function (Blueprint $table) {
$table->dropColumn('price_old');
});
}
}
Run that migration for creating a new column:
php artisan migrate

Change the datatype in the column with data in laravel migration

This is the migration? i have to change the string data column into integer data column with existing data
public function up()
{
Schema::table('SYS_tenants' ,function (Blueprint $table){
$table->integer('tena_type')->unsigned()->nullable()->change();
$table->foreign('tena_type')->references('id')->on('account_types');
});
}
As per laravel Documentation you can create a new migration and do it like this:
Schema::table('SYS_tenants', function (Blueprint $table) {
$table->integer('tena_type')->unsigned()->nullable()->change();
});
Before modifying a column, be sure to add the doctrine/dbal dependency
to your composer.json file.
composer require doctrine/dbal
Reference: Laravel -> Database: Migrations-> Modifying Columns
You can use change method on the field which you want to change the type after setting the new field type.
public function up() {
Schema::table('SYS_tenants' ,function (Blueprint $table){
$table->string('tena_type')->change();
});
}
I supposed the migration which create the table has already call all requirement you need like unique, nullable and so on. You can call change method, by the way there isn't restriction about any modification you want to perform like add other mysql index on that field.
Do not forget to add doctrine/dbal in composer.json file
Migrations#Modifying Columns
Looks like what you have should work:
Schema::table('SYS_tenants' ,function (Blueprint $table){
$table->integer('tena_type')->unsigned()->nullable()->change();
});
Depending on your database you may need to cast the values to the new type: (for mysql: https://www.mysqltutorial.org/mysql-cast/)
I already use this Laravel Migration
$table->integer('tena_type')->unsigned()->nullable()->change();
But it doesn't work because, the data already in the table. In that case it can't change the datatype.I use this DB statement to change the datatype with data.it's working properly.
DB::statement("alter table SYS_tenants modify tena_type integer not null"):

Migration - Cannot Change Double Data Type Value

I have an existing table created with this migration code:
Schema::create('mytable', function (Blueprint $table) {
$table->increments('id');
$table->double('mycolumn',8,2)->unsigned()->default(0);
$table->timestamps();
});
Then I have created another migration file to adjust the value range of my mycolumn field with the migration file below.
Schema::table('mytable', function (Blueprint $table) {
$table->double('mycolumn',15,2)->unsigned()->default(0)->change();
});
However I am getting an error:
In DBALException.php line 283:
Unknown column type "double" requested. Any Doctrine type that you use has to be registered with \Doctrine\DBAL\Types\Type::addType(). You can get a li
st of all the known types with \Doctrine\DBAL\Types\Type::getTypesMap(). If this error occurs during database introspection then you might have forgott
en to register all database types for a Doctrine Type. Use AbstractPlatform#registerDoctrineTypeMapping() or have your custom types implement Type#getM
appedDatabaseTypes(). If the type name is empty you might have a problem with the cache or forgot some mapping information.
What am I missing?
the double cannot be changed the way you do for other types, you can fix it using Doctrine\DBAL\Type
You can fix it in this way:
use Doctrine\DBAL\Types\FloatType;
use Doctrine\DBAL\Types\Type;
public function up() {
if (!Type::hasType('double')) {
Type::addType('double', FloatType::class);
}
Schema::table('mytable', function($table) {
$table->double('mycolumn',15,2)->default(0)->change();
.....
});
}
You are missing this from the documentation
Only the following column types can be "changed": bigInteger, binary, boolean, date, dateTime, dateTimeTz, decimal, integer, json, longText, mediumText, smallInteger, string, text, time, unsignedBigInteger, unsignedInteger and unsignedSmallInteger.
So double cannot be changed.
I haven't tried but you can maybe use a RAW MySQL query like this, try it locally first of course:
DB::statement('alter table mytable modify mycolumn DOUBLE(15,2) DEFAULT 0');
I'm not sure if this will help, but you may use decimal or float instead of double in this case, though float will not work if you want a limited amount of decimal places.
So it will look like:
$table->decimal('mycolumn',15,2)->unsigned()->default(0)->change();

How to change datatype float to string in laravel migration

I am trying to change datatype of one of my field from float to string but i am facing an issue
SQLSTATE[42000]: Syntax error or access violation: 1064 You have
an error in your SQL syntax; check the manual that
corresponds to your MariaDB server version for the right syntax to use
near '' at line 1 (SQL: ALTER TABLE patient
MODIFY height varchar)
my migration:
public function up()
{
DB::statement('ALTER TABLE patient MODIFY height varchar');
}
How i can achieve my target:
Your help need here
public function up()
{
Schema::table('patient', function (Blueprint $table) {
$table->string('height')->change();
});
}
You can use laravel's change method :
public function up()
{
Schema::table('patient', function ($table) {
$table->string('height')->change();
});
}
Also your SQL syntax should be :
ALTER TABLE patient MODIFY height varchar(255);
Update :
As per the laravel's documentation :
Only the following column types can be "changed": bigInteger, binary, boolean, date, dateTime, dateTimeTz, decimal, integer, json, longText, mediumText, smallInteger, string, text, time, unsignedBigInteger, unsignedInteger and unsignedSmallInteger.
So Laravel's change will not work directly as you have a float column which laravel internally makes as double(8,2). Please update your raw SQL syntax using what I have given and try again.

How to change enum type column in laravel migration?

I am using Laravel 5.1 and I have a table called packages with this structure:
id int(11)
weight decimal(10,2)
weight_unit enum('Kg.', 'Gm.')
I would like to change the weight_unit enum to:
weight_unit enum('Grams','Kgs.','Pounds')
For this I create the following migration:
public function up()
{
Schema::table('packages', function ($table) {
$table->enum('weight_unit', array('Grams','Kgs.','Pounds'))->nullable()->change();
});
}
But when I run the migration I receive an error:
Unknown database type enum requested, Doctrine\DBAL\Platforms\MySqlPlatform
may not support it.
How can I change this enum?
Use the DB::statement method:
DB::statement("ALTER TABLE packages MODIFY COLUMN weight_unit ENUM('Grams', 'Kgs', 'Pounds')");
This worked for me when adding a new enum value to the modified enum column.
Add the following to the up() method:
DB::statement("ALTER TABLE packages MODIFY weight_unit ENUM('Grams', 'Kgs', 'Pounds', 'new value') NOT NULL");
Then in the down() method you can revert the change that was made:
DB::statement("ALTER TABLE packages MODIFY weight_unit ENUM('Grams', 'Kgs', 'Pounds') NOT NULL");
Note: before the enum value is removed it needs to be changed to another enum value that will be retained.
$table->enum('level', ['easy', 'hard']);
You can add custom constructor to migration and explain to Doctrine that enum should be treated like string.
public function __construct(\Doctrine\DBAL\Migrations\Version $version)
{
parent::__construct($version);
$this->platform->registerDoctrineTypeMapping('enum', 'string');
}
In case you dont want to lose your data and update it with the new values I came up with this solution:
// Include old and new enum values
DB::statement("ALTER TABLE packages MODIFY COLUMN weight_unit ENUM('Kg.', 'Gm.', 'Grams', 'Kgs', 'Pounds')");
// Replace Kg. with Kgs
Packages::where('weight_unit', 'Kg.')->update(['weight_unit' => 'Kgs']);
// Replace Gm. with Grams
Packages::where('weight_unit', 'Gm.')->update(['weight_unit' => 'Grams']);
// Delete old values
DB::statement("ALTER TABLE packages MODIFY COLUMN weight_unit ENUM('Grams', 'Kgs', 'Pounds')");
This way you can replace your old values with the new ones.
add this before change() call :
DB::getDoctrineSchemaManager()->getDatabasePlatform()->registerDoctrineTypeMapping('enum', 'string');
I think that is fixed on Laravel 10 by adding support for native column modifying.
https://github.com/laravel/framework/pull/45487
So from Laravel 10 you can do this:
Schema::table('jobs', function (Blueprint $table) {
$table->enum('type', ['contract', 'permanent', 'partial'])->change();
});
I tried the same migration on fresh Laravel 9.55.0 and 10.0.2 application:
laravel-9.52.0.jpg
laravel-10.0.2.jpg
I am able to solve this by removing and adding constraints. This has made sure that my existing data is also is intact.
DB::statement("ALTER TABLE purchases DROP CONSTRAINT purchases_ref_check");
$types = ['single', 'monthly', 'biannual', 'amount', 'other'];
$result = join( ', ', array_map(function( $value ){ return sprintf("'%s'::character varying", $value); }, $types) );
DB::statement("ALTER TABLE purchases add CONSTRAINT purchases_ref_check CHECK (ref::text = ANY (ARRAY[$result]::text[]))");
with default value. add this in up():
\DB::statement("ALTER TABLE `patient_appointments` CHANGE `status` `status` ENUM('pending','wait','approved', 'consulted') CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'pending';");

Resources