I met what I believe is a very common problem with mysql and e-commerce shop ... though I can't find answer for this.
I've got shop which has not one product table but many ... for example in one shop has vinyls, studio gear etc ... so we've got many tables with different product details ... the thing is I need to get total amount (price) of products in cart from many tables
public static function GetTotalAmount() {
$params = array(
':cart_id' => self::GetCartId()
);
$sql = 'SELECT SUM(v.price) AS total_amount '.
'FROM shopping_cart sc '.
'INNER JOIN vinyl v '.
'ON sc.product_id = v.id AND sc.department_id = 1 '.
'WHERE sc.cart_id = :cart_id AND sc.buy_now;';
$v = DataBase::FetchOne($sql, $params);
$sql = 'SELECT SUM(sg.price) AS total_amount '.
'FROM shopping_cart sc '.
'INNER JOIN studio_gear sg '.
'ON sc.product_id = sg.id AND sc.department_id = 2 '.
'WHERE sc.cart_id = :cart_id AND sc.buy_now;';
$sg = DataBase::FetchOne($sql, $params);
return $sg + $v;
}
As you might see I made this with ugly way .. maybe you can help me show how to get SUM() of possible N tables counted from N.price.
You can use UNION ALL
SELECT SUM(price) FROM ((SELECT SUM(price) as price FROM table1 WHERE ...) UNION ALL (SELECT SUM(price) as price FROM table2 WHERE ...) UNION ALL ....)
A quick tip (if you can) - merge all the products tables into one table and operate on that (you'll also have to implement categories and custom attributes for products though). Otherwise you will have a mess when you add new shops.
You can create a (materialized) view with just the necessary columns of the product tables, - product_id and price
Once you have the view (vw_products) you can just do an inner join of shopping cart table with the view and then get the sum.
SELECT sum(vw.price) FROM
shopping_cart sc INNER JOIN vw_products vw
ON sc.product_id = vw.id and sc.department_id IN (1,2,...)
WHERE sc.cart_id = :cart_id AND sc.buy_now;
If you have many rows and if the prices don't change often (every few minutes)
I would suggest creating a table and populating it with the result of above query.
Every day or after every change to price you can refresh this table.
Related
I have four tables named tblproducts, tblprospecification, tblcomspecification and tblledtvpecification.
The fields of tblproducts are proid, product_code, product_name,
pro_img, pro_resize_img, pro_thumb_img and it stores products
details.
The second table is tblprospecification stores the mobile specifications and it has column speid, proid, in_the_box ,model_number, model_name, color, browse_type, sim_type.
The third table is tblcomspecification for storing computer specification and its column are comspecificid,proid, modelname, color, series etc. and the fourth column istblledtvpecification for storing ledtv specification and its column are tvspecificid, modelname, dsize, stype_id, hd_techno.
I am using the query below enter
$query= $this->db->select( 'tblproducts.proid as pro_id, product_code, product_name, pro_img, pro_resize_img, pro_thumb_img, tblprospecification.proid as product_id , in_the_box ,model_number, model_name, tblprospecification.color as mobile_color, browse_type, sim_type ,tblcomspecification.proid as product_id, tblcomspecification.modelname as com_moledname, series, tblcomspecification.color as com_color, tblledtvpecification.proid, tblledtvpecification.modelname as ledtv_modelname, dsize,stype_id, hd_techno')
->from('tblproducts')
->join('tblprospecification','tblproducts.proid = tblprospecification.proid ' ,'left')
->join('tblcomspecification','tblproducts.proid = tblcomspecification.proid', 'left')
->join('tblledtvpecification','tblproducts.proid = tblledtvpecification.proid' ,'left')
->where('tblproducts.proid',$proid)
->get();
return $query->result();
When I execute the query, it will return the data after join from tblproducts and tblprospecification only. It returns blank data for tblledtvpecification, tblcomspecification.
! have three table
inventories
enter image description here
warehouses
enter image description here
inventory_has_warehouses
enter image description here
I have use laravel yajra datatable. i need sum and search of starting_balance this field in inventory_has_warehouses pivot table
my code:
$id = Auth::user()->id;
$row = Inventory::with('contact')->with('warehouse')
->select(
'inventories.*',
DB::raw('SUM(inventory_has_warehouses.starting_balance) as total')
)
->leftJoin('inventory_has_warehouses', 'inventory_has_warehouses.inventory_id', '=', 'inventories.id')
->leftJoin('warehouses', 'warehouses.id', '=', 'inventory_has_warehouses.warehouse_id')
->where('inventories.subscriber_id',$id)
->groupBy('inventories.id');
$datatable = DataTables::of($row)
->filterColumn('total', function($query, $keyword) {
$query->whereRaw('sum(inventory_has_warehouses.starting_balance) like ?', ['%'.$keyword.'%']);
})
return $datatable->make(true);
but i fount this type of error
Exception Message:↵↵SQLSTATE[HY000]: General error: 1111 Invalid use
of group function (SQL: select count() as aggregate from (select
inventories., SUM(inventory_has_warehouses.starting_balance) as
total from inventories left join inventory_has_warehouses on
inventory_has_warehouses.inventory_id = inventories.id left
join warehouses on warehouses.id =
inventory_has_warehouses.warehouse_id where
inventories.subscriber_id = 2 and inventories.status = 1 and
(LOWER(inventories.itemcode) LIKE %1% or
LOWER(inventories.purchasedescription) LIKE %1% or exists (select
* from contacts where inventories.supplier = contacts.id and LOWER(contacts.name) LIKE %1%) or
(sum(inventory_has_warehouses.starting_balance) like %1%)) group by
inventories.id) count_row_table)
mysql query
select inventories., SUM(inventory_has_warehouses.starting_balance)
as total from inventories left join inventory_has_warehouses on
inventory_has_warehouses.inventory_id = inventories.id left join
warehouses on warehouses.id = inventory_has_warehouses.warehouse_id
where inventories.subscriber_id = 2 and inventories.status = 1 and
(LOWER(inventories.itemcode) LIKE %1% or
LOWER(inventories.purchasedescription) LIKE %1% or exists (select *
from contacts where inventories.supplier = contacts.id and
LOWER(contacts.name) LIKE %1%) or
(sum(inventory_has_warehouses.starting_balance) like %1%)) group by
inventories.id
$id = Auth::user()->id;
$row = DB::table('inventories')->select('inventories.*','contacts.name',DB::raw('SUM(inventory_has_warehouses.starting_balance) as total'))
->leftJoin('contacts', 'inventories.supplier', '=', 'contacts.id')
->leftJoin('inventory_has_warehouses', 'inventories.id', '=', 'inventory_has_warehouses.inventory_id')
->where('inventories.subscriber_id',$id)
->groupBy('inventory_has_warehouses.inventory_id');
if ($keyword = $request->get('search')['value']) {
$row->having(DB::raw('SUM(inventory_has_warehouses.starting_balance)'), 'like', '%'.$keyword.'%');
$row->orHaving('inventories.itemcode', 'like', '%'.$keyword.'%');
$row->orHaving('inventories.purchasedescription', 'like', '%'.$keyword.'%');
$row->orHaving('contacts.name', 'like', '%'.$keyword.'%');
}
$datatable = DataTables::of($row)
->filterColumn('total', function($query, $keyword) {
})
return $datatable->make(true);
try to group by inventory_has_warehouses.inventory_id
Edited answer:
Your really giving hardtime for someone to read your query and give you help but to correct your query here is a reformatted query with corrections:
SELECT
inventories.*,
SUM(inventory_has_warehouses.starting_balance) as total
FROM
inventories LEFT JOIN inventory_has_warehouses
ON
inventory_has_warehouses.inventory_id = inventories.id LEFT JOIN warehouses
ON
warehouses.id = inventory_has_warehouses.warehouse_id
WHERE
inventories.subscriber_id = 2
AND
inventories.status = 1
AND
(LOWER(inventories.itemcode) LIKE '%1%' or LOWER(inventories.purchasedescription)
LIKE '%1%' OR EXISTS
(SELECT
*
FROM
contacts
WHERE
inventories.supplier = contacts.id
AND
LOWER(contacts.name) LIKE '%1%')
OR
(SUM(inventory_has_warehouses.starting_balance) LIKE '%1%')) GROUP BY inventories.id
the problem with query you sent is your like statement only have this:
LIKE %1%
this statement expects strings and it only says:
inventories.
this should be specific to a column you need or just use inventories.* to display all columns of that table but the error still doesn't make sense because it says and:
select count() as aggregate
maybe one of those would solve but upon reformatting your code I notice firstly the syntax error but this is very basic maybe you can start on just running a very simple query for the moment this might be the query that would work for you:
SELECT
inventories.id AS inventory_id,
warehouses.id,
SUM(inventory_has_warehouses.starting_balance) AS total
FROM
inventories LEFT JOIN inventory_has_warehouses
ON inventories.id = inventory_has_warehouses.inventory_id
LEFT JOIN
warehouses
ON warehouses.id = inventory_has_warehouses.warehouse_id
GROUP BY
inventory_has_warehouses.inventory_id
from this start adding the conditions one by one until the error appears again (do this on mysql query window not through laravel code) not yet sure how laravel handles sql queries but the format you sent will really cause an error and also if your going to post a question here make sure to make it reader friendly or someone might slam you cause its hard to read a code that is not properly formatted. ;)
also one thing I forgot make sure that the inventories.id is the primary key of that table or this will still cause you an error refer to this link for more details https://dev.mysql.com/doc/refman/5.7/en/group-by-handling.html
Just to clarify i can't change the tables structure, so please leave out the "you should change your tables to this and that" answers, thank you.
So i have a table entities_attributes_values where an entity has a lot of attributes and the value of that attribute, basically imagine 3 fields:
entity_id
entity_attributes_id
value
Because every entities attribute and its value is on row getting more values is not so easy i was thinking of multiple self joins, and because this query will be very common i created a view, which is built with this query:
SELECT `L1`.`entity_id`,
`L1`.`value` as 'company_id',
`L2`.`value` as 'entity_name',
`P`.`value` as 'person_name',
`L4`.`value` as 'establishment_id',
`L5`.`value` as 'department_id'
FROM `entities_attributes_values` `L1`
LEFT JOIN `entities_attributes_values` `L2` ON `L1`.`entity_id` = `L2`.`entity_id` AND `L2`.`entity_attributes_id` = 1
LEFT JOIN `entities_attributes_values` `L3` ON `L1`.`entity_id` = `L3`.`entity_id` AND `L3`.`entity_attributes_id` = 3
LEFT JOIN `persons_attributes_values` `P` ON `L3`.`value` = `P`.`core_persons_id` AND `P`.`core_persons_attributes_id` = 4
LEFT JOIN `entities_attributes_values` `L4` ON `L1`.`entity_id` = `L4`.`entity_id` AND `L4`.`entity_attributes_id` = 12
LEFT JOIN `entities_attributes_values` `L5` ON `L1`.`entity_id` = `L5`.`entity_id` AND `L5`.`entity_attributes_id` = 13
WHERE `L1`.`entity_attributes_id` = 2
So this works but i have one problem i get "duplicate" values and its not really duplicate but the point is that in my view i want every entity to be only one row with all its attributes values but instead i get this:
So as you can see the first three result are not good for me, i only need the fourth one, where i have all my data about one entity.
Thank you in advance for any help!
Try using conditional aggregation instead:
select eav.entity_id,
max(case when entity_attributes_id = 2 then eav.value end) as company_id,
max(case when entity_attributes_id = 1 then eav.value end) as entity_name,
max(case when entity_attributes_id = 3 then eav.value end) as company_name,
. . .
from entities_attributes_values eav
group by eav.entity_id;
This will make it easy to add new attributes to the view. Also, don't use single quotes to delimit column names. Single quotes should only be used for date and time constants.
I have this query made in codeigniter using active record
$this->db->select('products_main.*, images_main.*, items_main.*, product_tags.*');
$this->db->from('products_main');
$this->db->join('images_main','products_main.product_tag = images_main.img_tag AND products_main.product_id = images_main.pro_img_id');
$this->db->join('items_main','products_main.product_id = items_main.pro_items_id');
$this->db->join('product_tags','products_main.product_id = product_tags.pro_tag_id');
$this->db->where('products_main.product_id',$p_id);
$this->db->where('products_main.status','active');
$this->db->group_by('products_main.product_id');
$query = $this->db->get();
My goal is to:
Grab one product from products_main that matches the input from $p_id
Grab all the photos for that one product from the images_main table
Grab all the items that have the product_id of the product I have found
Grab the row in the product_tags table that match the product_id of the product i have found.
I started a test fiddle here but have not filled out the query part yet as I do not know what to put. fiddle
You don't have any problem within your query, but as you group by product id, you may only get one result, but you can group by image_id instead, i've created the same in my localhost with the database you've created a fiddle and tried your solution, your only problem i see was as you don't join on left, the query can't find any exact matches, so try to join on left, also i've changed your query a little bit to prevent the database error with the given structure in your fiddle, so change it if you have them like that in your database ( commented them ) :
$this->db->select('p.*, im.*, i.*, pt.*');
$this->db->from('products_main as p');
// img_tag -> image_tag
$this->db->join('images_main as im',
'p.product_tag = im.image_tag
AND p.product_id = im.product_id','left'); // pro_img_id -> product_id
$this->db->join('items_main as i',
'p.product_id = i.product_id','left'); // pro_items_id -> product_id
$this->db->join('product_tags as pt',
'p.product_id = pt.product_id','left'); // pro_tag_id -> product_id
$this->db->where('p.product_id',"23"); // i have given example id as 23
$this->db->where('p.status','active');
$query = $this->db->get();
return $query->result_array();
this is my database
database schema http://slashdir.com/php/blogg/images/bloggdb.png
What i want to do, is, for a given userid, show the total times he has been reported.
I have read various other questions on the matter, but I'm still stumped.
The latest query i tried was
select
sum(posts.timesreported + comments.timesreported) AS total_reports
FROM
posts
INNER JOIN comments ON (posts.userid = comments.userid)
WHERE posts.userid=5 AND comments.userid=5;
But this must be wrong as the number i get is much too high
Thanks!
SELECT
CASE WHEN NULL
THEN 0
ELSE (select sum(posts.timesreported) AS total_posts_reports
FROM posts INNER JOIN users ON (posts.userid = users.id)
WHERE posts.userid=5)
END
+
CASE WHEN NULL
THEN 0
ELSE (select sum(comments.timesreported) AS total_comments_reports
FROM comments INNER JOIN users ON (comments.userid = users.id)
WHERE comments.userid=5)
END
FROM DUAL;
Instead of
sum(posts.timesreported + comments.timesreported) AS total_reports
try
sum(posts.timesreported) + sum(comments.timesreported) AS total_reports
and I think you need to group by userId
WHERE posts.userid=5 AND comments.userid=5; is unnecessary since the tables are joined.
And sum operator is not correct logically
Use this query
select
sum(posts.timesreported) + sum(comments.timesreported) AS total_reports
FROM
posts
INNER JOIN comments ON (posts.userid = comments.userid)
WHERE posts.userid=5
It looks like your collecting the sum PRIOR to singling out the user. Perhaps this is adding those column values for all users prior to the join? What happens if you SELECT *, perform your INNER JOIN where userid = 5. Save the column values as two variables and then try to add them. Do you get the same result?
This might help you error check to see if the above theory is accurate.
<?php
// Connects to your Database
mysql_connect("your.hostaddress.com", "username", "password") or die(mysql_error());
mysql_select_db("Database_Name") or die(mysql_error());
//Run Query
$NUM1=mysql_query("SELECT Field1 FROM Table WHERE user.key=5");
$NUM2=mysql_query("SELECT Field2 FROM Table WHERE user.key=5");
//Print Each Result
echo 'Num1 = '.$NUM1;
echo 'Num2 = '.$NUM2;
//Print Total
$TOTAL = $NUM1 + $NUM2;
echo 'Total = '.$TOTAL;
?>