Refactor database schema on migration - php

This is my initial migration
Schema::create('orders', function (Blueprint $table) {
$table->id();
$table->String('customer_name');
$table->String('customer_phone');
//others
});
Now, the easy time ended and now I have to move name and phone to customer table. This is my create customer migration. I don't know where to do this operation so I just throw all in the migration.
Schema::create('customers', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('phone', 15);
//others
});
$users = DB::table('orders')->select(['customer_name', 'customer_phone'])->distinct()->get();
foreach ($users as $user) {
$attr['name'] = $user->customer_name;
$attr['phone'] = $user->customer_phone;
Customer::create($attr);
}
And alter order migration
Schema::table('orders', function (Blueprint $table) {
$table->unsignedBigInteger('customer_id')->nullable()->after('id');
$table->foreign('customer_id')->references('id')->on('customers');
});
Now I'm stuck with empty customer_id. I have no clue what to do next, except manually insert it by referring to two table, which can take too much time to update hundreds of rows.

Try use this statement on up function.
DB::statement("UPDATE `orders` o SET `customer_id` = (SELECT `id` FROM `customers` WHERE `name` = o.customer_name AND `phone` = o.customer_phone)");
And you might want to drop those two column. Throw this too.
Schema::table('orders', function (Blueprint $table) {
$table->dropColumn(['customer_name', 'customer_phone']);
});

Related

Problem with making relationships using Laravel migrations

I have problem with Laravel migrations. I want to make a relationship between two tables but
I am getting error General error: 1005 Can't create table
eshopper.prices (errno: 150 "Foreign key constraint is incorrectly
formed") (SQL: alter table prices add constraint pri ces_product_id_foreign foreign key (product_id) references
products (id) .
Here is my code. Tables are prices and products.
Prices
public function up()
{
Schema::create('prices', function (Blueprint $table) {
$table->id();
$table->float('amount');
$table->unsignedBigInteger('product_id')->unsigned()->index();
$table->foreign('product_id')->references('id')->on('products')->onUpdate('cascade')->onDelete('cascade');
$table->timestamps();
});
}
Products
public function up()
{
Schema::create('products', function (Blueprint $table) {
$table->id();
$table->string("title",100);
$table->text("description");
$table->timestamps();
});
}
NOTE: In my migrations products table is under prices table, I know that the first created table is prices than products and that is error.
My question is do I have to put products frst or I can keep same layout(prices first, than products) and change something in code?
it happens because the product_id field type is different from the id field in the products table, try this in the products migration file:
public function up()
{
Schema::create('products', function (Blueprint $table) {
$table->unsignedBigInteger('id', true); // true here means it's auto incremental
$table->string("title",100);
$table->text("description");
$table->timestamps();
});
}
Instead of putting the constraints inside the migration file of price you can put it inside the migration file of products. Since it will create the prices table first before the products the constraints will not be created because the products table is not yet created.
/**
* This is the prices table
*
* it depends in you if you want to define the column here directly without its constraints
* the commented column is optional
*/
public function up()
{
Schema::create('prices', function (Blueprint $table) {
$table->id();
$table->float('amount');
//$table->unsignedBigInteger('product_id');
$table->timestamps();
});
}
public function up()
{
Schema::create('products', function (Blueprint $table) {
$table->id();
$table->string("title",100);
$table->text("description");
$table->timestamps();
});
// you can define your constraints here
Schema::table('prices', function(Blueprint $table) {
$table->foreignId('product_id')
->constrained('products')
->cascadeOnDelete()
->cascadeOnUpdate();
// if you uncomment the column commented on the prices table instead of the one at above you can use this instead
$table->foreign('product_id')
->references('id')
->on('products')
->cascadeOnDelete()
->cascadeOnUpdate();
});
}
Short answer is that you MUST put products first before prices. If the whole code is still in development and have yet to get deployed, then the easiest solution is to rename the products table migration so that it has older timestamp than the prices migration has.

Change Primary ID in laravel Migration

I'm creating a table where I want to use the ID from this table "menu_items" to be added in another table
Table one: menu_items
Schema::create('menu_items', function (Blueprint $table) {
$table->id('menu_level_item_id');
$table->timestamps();
$table->string('menu_item_name');
$table->string('menu_item_desc');
Table 2 products
Schema::create('products', function (Blueprint $table) {
$table->id();
$table->string('product_name');
$table->string('product_desc');
$table->integer('price');
$table->integer('menu_level_item_id');
$table->timestamps();
});
My aim of doing this is that I can then create a relationship between the 2 tables as they have the same key?
Is there a different approach I can take? Should I create a unique key when creating a menu item and then add this to the second table?
Thank you.
Basically Laravel Eloquent do the key handling. When you have two tables which both has as key the name id, this is not a problem. Name the keys in the relation table just like this
table1_id
table2_id
Laravel will handle this in Eloquent. You are also able to name the two columns in the relation table to what ever you want. You could define it for the relation in Eloquent. E.g.
public function otherModel () {
return $this->belongsToMany('App\Models\OtherModel', 'table_name', 'this_model_id', 'other_model_id');
}
Please have a look into:
Laravel Relationship Documentation
Schema::create('menu_items', function (Blueprint $table) {
$table->id();
$table->timestamps();
$table->string('menu_item_name');
$table->string('menu_item_desc');
table->timestamp();
});
Schema::create('products', function (Blueprint $table) {
$table->id();
$table->string('product_name');
$table->string('product_desc');
$table->integer('price');
$table->unsignedBigInteger('menu_level_item_id');
$table->timestamps();
$table->foreign('menu_level_item_id')->references('id')->on('menu_items');
});

Select statement with group_concat not working when other columns are called in laravel

Hello my laravel code is
$productDetails = DB::table('products')
->select(DB::raw('products.name, GROUP_CONCAT(sizes.name) as sizesName'))
->join('subcategories', 'products.subcategories_id', '=', 'subcategories.id')
->join('size_categories', 'subcategories.categories_id', '=', 'size_categories.categories_id')
->join('sizes',function($join){
$join->on(DB::raw("FIND_IN_SET(sizes.id, size_categories.size_id)"),">",DB::raw("'0'"));
})
->where('products.id', $request->id)
->get();
This doesnt work, when i useproducts.name or any other column name in select statement
but when i use only group_concat inside Db::raw and nothing else, the query works.
So how do i fetch other columns?
Please help.
I am stuck on it for quite a while
The query i want is
select GROUP_CONCAT(sizes.name),`products`.`name`, `products`.`image`, `products`.`id`, `products`.`image_second`, `products`.`description`, `products`.`min_order`, `size_categories`.`size_id` from `products`
inner join `subcategories` on `products`.`subcategories_id` = `subcategories`.`id`
inner join `size_categories` on `subcategories`.`categories_id` = `size_categories`.`categories_id`
join sizes on (FIND_IN_SET(sizes.id,size_categories.size_id)>0) where `products`.`id` = '7'
Please note that the above query is working fine. I just cant make it in laravel to work. Only the group_concat part.
This is the screenshot from my database, when i dont use group_concat
Also the DISTINCT part is doing nothing there, please ignore it.
I was just trying that out
This is the migration of create_products_table
public function up()
{
Schema::create('products', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('units_id');
$table->unsignedBigInteger('selections_id');
$table->unsignedBigInteger('subcategories_id');
$table->string('name');
$table->string('image');
$table->text('description');
$table->string('min_order');
$table->timestamps();
$table->index('units_id');
$table->index('selections_id');
$table->index('subcategories_id');
});
}
migration of create_subcategories_table
public function up()
{
Schema::create('subcategories', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->unsignedBigInteger('categories_id');
$table->timestamps();
$table->index('categories_id');
});
}
data of size_categories table
public function up()
{
Schema::create('size_categories', function (Blueprint $table) {
$table->id();
$table->string('size_id');
$table->unsignedBigInteger('categories_id');
$table->timestamps();
$table->index('categories_id');
});
}
migration of categories table
public function up()
{
Schema::create('categories', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->timestamps();
});
}
migration of sizes table
public function up()
{
Schema::create('sizes', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->timestamps();
});
}
In sizes table data is in this form
id name
1 2m
2 3m
3 4m
First, you need to specify select columns separately. Like so:
->select(DB::raw('products.name'), DB::raw('GROUP_CONCAT(sizes.name) as sizesName'))
Next, since group concat is an aggregate column, you need to group the sizes, and product name since it's in the select list and it is not related to size.
->groupBy('size_categories.size_id', 'products.id') //edit after your comment. group by prodcuts.id to be able to select columns from products table.
So your final query should look like this:
$productDetails = DB::table('products')
->select(DB::raw('products.name'), DB::raw('GROUP_CONCAT(sizes.name) as sizesName'))
->join('subcategories', 'products.subcategories_id', '=', 'subcategories.id')
->join('size_categories', 'subcategories.categories_id', '=', 'size_categories.categories_id')
->join('sizes',function($join){
$join->on(DB::raw("FIND_IN_SET(sizes.id, size_categories.size_id)"),">",DB::raw("'0'"));
})
->where('products.id', 7)
->groupBy('size_categories.size_id', 'products.id')
->get();

How to implement a combined cross and inner joins in Laravel?

I have defined 3 tables in Laravel as follow:
Schema::create('locales', function (Blueprint $table) {
$table->string('id', 2);
$table->string('name', 5000);
$table->timestamps();
$table->primary('id');
});
Schema::create('i18n_keys', function (Blueprint $table) {
$table->string('id', 255);
$table->timestamps();
$table->primary('id');
});
Schema::create('i18ns', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('key', 255);
$table->string('locale', 2);
$table->string('translation', 5000)->nullable();
$table->timestamps();
$table->foreign('key')->references('id')->on('i18n_keys')->onDelete('cascade')->onUpdate('cascade');
$table->foreign('locale')->references('id')->on('locales')->onDelete('cascade')->onUpdate('cascade');
$table->unique(array('key', 'locale'));
});
Now the question is how can I implement the following SELECT statement in Laravel programmatically. I mean without running the SQL statement directly.
SELECT `il`.`key`, `il`.`locale`, `in`.`translation` FROM
(SELECT `ik`.`id` AS `key`, `lo`.`id` AS `locale` FROM `i18n_keys` as `ik` CROSS JOIN `locales` as `lo`) AS `il`
left join `i18ns` as `in`
ON `in`.`key` = `il`.`key`
and `in`.`locale` = `il`.`locale`;
The aim is to extract the keys that they don't have a translation yet. But I like to do this with query builder or eloquent or something similar rather than pass the query directly. Is there any way?
You can try this code:
use App\Models\I18nKey;
$ik = I18nKey::crossJoin('locales as lo')
->select('i18n_keys.id AS key', 'lo.id AS locale');
$res = \DB::table(\DB::raw("({$ik->toSql()}) AS il"))
->mergeBindings($ik->getQuery())
->leftjoin('i18ns as in',function($join){
$join->on('in.key', '=', 'il.key')
->whereColumn('in.locale', 'il.locale');
})->select('il.key','il.locale','in.translation')->get();

How to do join in different names in Laravel?

I have two tables named users and buys:
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('first_name');
$table->string('last_name');
$table->string('referral_code')->nullable();
$table->integer('parent_id')->unsigned()->nullable();
$table->string('mobile')->unique();
$table->string('email')->unique();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
}
public function up()
{
Schema::create('buys', function (Blueprint $table) {
$table->bigIncrements('id');
$table->bigInteger('user_id')->unsigned();
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$table->bigInteger('product_id')->unsigned();
$table->foreign('product_id')->references('id')->on('products')->onDelete('cascade');
$table->timestamps();
});
}
I want to do a join on users.parent_id and buys.user_id. Here is my current query:
public function user ()
{
return $this->hasOne(User::class);
}
My query:
$users = Buy::all()->where('parent_id', auth()->user()->id)->latest()->paginate(25);
But my query throws this:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'parent_id' in 'where clause' (SQL: select count(*) as aggregate from buys where parent_id = 2)
Any idea how can I fix it?
When making the relationship, Laravel expects that the foreign key name will be the method name + _id in your case user_id which is okay for the local key, but the foreign key is not the id on the user table, so you need to tell Laravel that. So try this instead:
public function user ()
{
return $this->hasOne(User::class, 'parent_id', 'user_id');
}
-- EDIT after seeing your query
You are trying to use a column that does not exist on your buys model.
$users = Buy::with('user')->where('user_id', auth()->user()->id)->latest()->paginate(25);
It should be like
$users = Buy::where('user_id', auth()->user()->parent_id)->latest()->paginate(25);

Categories