Pull result for missing data - mysql

How to match and product_id in the query
atm the query is pull only missing result but each product have his own record and need to match with this record
This query work right but isn't match product_id
SELECT oc_ekstri_frontend.*,
oc_ekstri_image.id as img_id,
oc_ekstri_image.name
FROM oc_ekstri_image
LEFT JOIN oc_ekstri_frontend ON (oc_ekstri_frontend.id = oc_ekstri_image.frontend_id)
LEFT JOIN oc_ekstri_frontend_view ON (oc_ekstri_frontend_view.ekstri_id = oc_ekstri_image.id)
WHERE oc_ekstri_frontend.subcat_id = '" . $id . "'
AND oc_ekstri_frontend_view.ekstri_id IS NULL
How will I match for current product_id?
I tried something like this to add to the query but isn't work result is empty
AND oc_ekstri_frontend_view.product_id = '" . $product_id . "'

Without seeing your data or your expected output, it is hard to give an exact answer. One possible solution might be to move your new restriction from the WHERE clause to the ON clause:
SELECT
f.*,
i.id AS img_id,
i.name
FROM oc_ekstri_image i
LEFT JOIN oc_ekstri_frontend f
ON f.id = i.frontend_id
LEFT JOIN oc_ekstri_frontend_view v
ON v.ekstri_id = i.id AND
v.product_id = ?
WHERE
f.subcat_id = ? AND
v.ekstri_id IS NULL;
I use ? placeholders in the above query to suggest that you use a prepared statement rather than concatenating in your parameters. If you don't know what prepared statements are in PHP, you should read about them.

Related

SQL IF ELSE WITH MULTIPLE SELECT STATEMENT

I want to optimize these SQL queries using if-else but how I should use it? .
if this query result contain 'ALL'
SELECT
bdsubcategory.subcategoryID as ID,
bdsubcategory.subcategoryName as Name
FROM
phonebook.newsms_subscription
INNER JOIN bdsubcategory ON bdsubcategory.subcategoryID = newsms_subscription.subcategoryID
INNER JOIN newsms_client ON newsms_subscription.clientID =newsms_client.clientID
INNER JOIN newsms_person ON newsms_subscription.personID = newsms_person.personID
WHERE
newsms_subscription.isActive = 1 AND
newsms_person.personID = '856'
Then i want to query this
SELECT
bdsubcategory.subcategoryID as ID,
bdsubcategory.subcategoryName as Name
FROM
phonebook.newsms_subscription
INNER JOIN bdsubcategory ON bdsubcategory.subcategoryID = newsms_subscription.subcategoryID
INNER JOIN newsms_person ON newsms_subscription.personID = newsms_person.personID
WHERE
newsms_subscription.isActive = 1
GROUP BY subcategoryName
ORDER BY subcategoryName
otherwise take query1 result .
The problem is that if we do not refactor your project, then you always have to evaluate query1 and see whether it contains All or not. If it does not contain All, then you need to evaluate query2 as well. This can hardly be optimized, let's see a few approaches:
Quickening query1
Since All might be not be the very last evaluated element, adding it to the filter and limiting it is a good idea to quicken query1:
SELECT
COUNT(*)
FROM
phonebook.newsms_subscription
INNER JOIN bdsubcategory ON bdsubcategory.subcategoryID = newsms_subscription.subcategoryID
INNER JOIN newsms_client ON newsms_subscription.clientID =newsms_client.clientID
INNER JOIN newsms_person ON newsms_subscription.personID = newsms_person.personID
WHERE
newsms_subscription.isActive = 1 AND
newsms_person.personID = '856' AND
bdsubcategory.subcategoryName = 'ALL'
LIMIT 0, 1
So, you could create a stored procedure which evaluates query1' (query1' is the quickened version of query1, as seen above) and if there is a result, then we need to execute query1. Otherwise we need to execute query2. This way you still execute two queries, but the first query is optimized.
Refactoring
Note that the second query does not change. You could create a table where you could cache its results, using a periodic job. Then, you could skip the second table to
SELECT ID, Name
FROM MyNewTable;
without the many joins. You would also cache the results of the first query into a table where the items having ALL would be stored and query that table.
One option would be to use a CASE.
Change this:
newsms_person.personID = '856'
To this:
'Y' = CASE WHEN UPPER('856') = 'ALL' THEN 'Y'
WHEN newsms_person.personID = '856' THEN 'Y'
ELSE 'N' END
Alternatively, a stored procedure could be used to first validate whether the personID seems valid, then returns the appropriate data.

How can (SUM) in pivot table field and searching that field in yajra-laravel-datatable package (laravel 5.6)

! 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

convert following MySQL query into codeigniter

How to write this query in codeigniter
SELECT U.username,U.user_id
FROM storylikes S, user U
WHERE U.user_id=S.user_id_fk AND S.user_id_fk='$id'
try this :
$this->db->select('u.username, u.user_id');
db->where('u. user_id = s.user_id_fk');
$this->db->where('s.user_id_fk = '.$id);
$query = $this->db->get('storylikes s, user u');
use $your_variable = $query->result(); for the result
you should use joins instead of this query
$this->db->select('username,user_id');
$this->db->from('user');
$this->db->join('storylike','storylike.user_id_fk = user.user_id');
$this->db->where('storylike.user_id','$id');
as long as the db helper is loaded... You dont need to do anything special
$query = $this->db->query('SELECT U.username,U.user_id FROM storylikes S, user U WHERE U.user_id=S.user_id_fk AND S.user_id_fk=$id);
Using a cartesian (cross join) by doing FROM with 2 tables can cause some unruly results if not used 'correctly'
I suggest that if you are trying to just join tables together your SQL should be
SELECT U.username,U.user_id
FROM storylikes S, user U
INNER JOIN user U ON S.user_id = U.user_id_fk
WHERE S.user_id_fk=$id
CI querybuilder for this would be:
$query = $this->db->select('U.username,U.user_id')
->join('user U', 'S.user_id = U.user_id_fk', 'inner')
->where('S.user_id', $id)
->get('user U');
Using the correct join for the correct requirements is key;
INNER JOIN to ensure both FROM and the JOIN table match 1 for 1...
LEFT JOIN if you want to ensure you have all data from your FROM table and any without results in the JOIN table show up as NULL
RIGHT JOIN (opposite of left), to grab all data from the JOIN table and only matching data from the FROM table.
CROSS (CARTESIAN) JOIN when you want to ... frankly... mash the data together... A CROSS JOIN will also function like an INNER JOIN when you stipulate criteria in the WHERE statement (like you did) but still, use the correct JOIN for the correct usage-case.
There are other available joins but those are the basics.

Subquery without where-clause

Here's my code
SELECT res.type,
res.contactname,
res.id,
res.inv_addressline2,
res.inv_addressline3,
res.signup_date,
res.engineer_id_global,
res.job_id_global,
res.neg_or_pos,
res.rating,
res.author_id_global,
res.timestamp_global,
res.short_description,
res.job_title,
res.feedback,
author_data.contactname AS `author_name`,
review_count.total_feedback,
review_count.total_rating
FROM (SELECT mb.type,
mb.contactname,
mb.id,
mb.inv_addressline2,
mb.inv_addressline3,
mb.signup_date,
fb.engineer_id AS `engineer_id_global`,
fb.timestamp AS `timestamp_global`,
fb.job_id AS `job_id_global`,
fb.neg_or_pos,
fb.rating,
fb.feedback,
fb.author_id AS `author_id_global`,
ac.engineer_id,
ac.timestamp,
ac.author_id,
jb.job_id,
SUBSTR(jb.job_description, 1, 200) AS `short_description`,
jb.job_title
FROM " . MEMBERS_TABLE . " AS mb
LEFT JOIN " . ACCEPTED . " AS ac
ON mb.id = ac.engineer_id
LEFT JOIN " . FEEDBACK . " AS fb
ON ac.job_id = fb.job_id
LEFT JOIN " . JOBS . " AS jb
ON fb.job_id = jb.job_id
WHERE mb.type = 2
ORDER BY
fb.timestamp DESC
) AS res
LEFT JOIN
(SELECT mb.id,
mb.contactname,
fb.author_id
FROM " . MEMBERS_TABLE . " AS mb
LEFT JOIN " . FEEDBACK . " AS fb
ON fb.author_id = mb.id
LIMIT 1
) AS `author_data`
ON res.author_id_global = author_data.author_id
LEFT JOIN
(SELECT COUNT(fb.engineer_id) AS `total_feedback`,
SUM(fb.rating) AS `total_rating`,
fb.engineer_id
FROM " . FEEDBACK . " AS fb
) AS `review_count`
ON res.engineer_id_global = review_count.engineer_id
GROUP BY res.contactname
ORDER BY res.contactname
I'm just starting to get my head around SQL. My worry is the second and third inner query. Am I right in saying it will return all results as there is no where clause and the return the results from that using the "ON" statement or is the "ON" statement combined with the initial query?
There are a number of issues with this script:
You have a number of tables with names like " . MEMBERS_TABLE . ", " . ACCEPTED . " and so on. These are unlikely to be acceptable in MySQL, which normally uses backticks (`) to quote object names; if this script is to be preprocessed by eg. Perl or Python, or is part of a larger script in another language, it would be helpful to say so.
You have an order by clause, for no apparent reason, in your first sub-query. This could be removed.
Your second sub-query links FEEDBACK to MEMBERS_TABLE and limits the results to 1, without specifying the author_id inside the sub-query - this means that a single, random member will be selected inside the sub-query, then linked to the rest of the dataset on the specific author ID, which won't match for most of the rest of the dataset.
The FEEDBACK table is completely irrelevant here, and can be removed.
If id uniquely identifies a record on MEMBERS_TABLE, the sub-query can be completely removed and replaced with a single left join to MEMBERS_TABLE on res.author_id_global = MEMBERS_TABLE.id. No limit clause would be required.
If id does not uniquely identify a record on MEMBERS_TABLE, the sub-query should be rewritten as select distinct id, contact_name FROM " . MEMBERS_TABLE . " AS mb where res.author_id_global = mb.id LIMIT 1. If there are multiple matching authors for the same id, one would be selected at random.
The third sub-query does not require a where clause - it will summarise all engineers' feedback and ratings by engineer within the sub-query, and each engineer will then be linked to the corresponding engineer from the rest of the dataset by the on condition from the left join clause.
Second inner query is having limit 1. It is nothing but where condition to show only one result. Third inner query is not having any problem.

Row counting a JOINed column without affecting the returned rows?

It's a bit difficult getting my problem into a short form, so I apologise if the title doesn't make sense.
Anyway, here is the problem:
$query = '
SELECT issues.*, comments.author AS commentauthor, favorites.userid AS favorited FROM issues
LEFT JOIN comments ON comments.issue = issues.id AND comments.when_posted = issues.when_updated
LEFT JOIN favorites ON favorites.ticketid = issues.id AND favorites.userid = \'' . $_SESSION['uid'] . '\'
' . $whereclause . '
ORDER BY issues.when_updated ' . $order;
Don't mind the fact that it's PHP as I am not asking for PHP help.
The query retrieves a bunch of issues, and what I'm wishing to do is obtain the row count of favorites that have favorites.ticketid matching issues.id. My use of LEFT JOIN favorites is not to get what I've just mentioned, but instead to obtain whether the client has favourited the issue, thus the part favorites.userid AS favorited.
I have tried doing the following: (all at once, I'm putting this in bulleted form for readibility)
duplicating the existing LEFT JOIN favorites and removing the user id check from the duplicate
adding , COUNT(favorites.ticketid) AS favoritescount to the SELECT section
adding AS favorited to the original LEFT JOIN as well as changing favorites.userid to favorited.userid
With that attempt, my query ends up returning only one row.
SELECT issues.*,
comments.author AS commentauthor,
favorites.userid AS favorited,
(
SELECT COUNT(favorites.id)
FROM favorites
WHERE ticketid = issues.id
) AS numfavorites
FROM issues
LEFT JOIN comments
ON comments.issue = issues.id
AND comments.when_posted = issues.when_updated
LEFT JOIN favorites
ON favorites.ticketid = issues.id
AND favorites.userid = ?uid
That should work, I'm just using a subquery to get number of favourites