How to insert a max value plus one in mysql in opencart - mysql

I have the following:
Model File
$max = $this->db->query("SELECT MAX( sort ) FROM lc_menu");
print_r($max);
Printed Values
stdClass Object ( [num_rows] => 1 [row] => Array ( [MAX( sort )] => 64 )
[rows] => Array ( [0] => Array ( [MAX( sort )] => 64 ) ) )
How can I insert max+1 in MySQL query?

You can use subquery:
$this->db->query('INSERT INTO ' . DB_PREFIX . ' menu SET
menuname = "$this->db->escape($data['menuname'])",
start_date = "$this->db->escape($data['start_date'])",
start_time = "$this->db->escape($data['start_time'])",
end_date = "$this->db->escape($data['end_date'])",
end_time = "$this->db->escape($data['end_time'])",
link_value = "$this->db->escape($data['link_value'])",
link = "$this->db->escape($alpha['link'])",
sort = ((SELECT MAX(sort) FROM lc_menu) + 1)');

Related

Order query by subquery. Eloquent vs MySql

I would like to get lists which are followed by a particular user and order lists by created_at(by date when lists were followed). Not sure why it doesn't work (order by) using Eloquent:
$myQuery = PlaceList::query()
->where('private', 0)
->whereHas('followers', function ($query) use ($userID) {
$query->where('created_by_user_id', $userID);
})
->orderByDesc(
Follow::query()->select('created_at')
->where('created_by_user_id', $userID)
->where('followable_id', 'place_lists.id')
)
->get()
This is what I've got when I use dd($myQuery->toSql()):
select
*
from
`place_lists`
where
`private` = ?
and exists (
select
*
from
`follows`
where
`place_lists`.`id` = `follows`.`followable_id`
and `created_by_user_id` = ?
and `follows`.`deleted_at` is null
)
and `place_lists`.`deleted_at` is null
order by (
select
`created_at`
from
`follows`
where
`created_by_user_id` = ?
and `followable_id` = ?
and `follows`.`deleted_at` is null
) desc
But when I populate MySql with data it does work:
select
*
from
`place_lists`
where
`private` = 0
and exists (
select
*
from
`follows`
where
`place_lists`.`id` = `follows`.`followable_id`
and `created_by_user_id` = 13
and `follows`.`deleted_at` is null
)
and `place_lists`.`deleted_at` is null
order by (
select
`created_at`
from
`follows`
where
`created_by_user_id` = 13
and `followable_id` = `place_lists`.`id`
and `follows`.`deleted_at` is null
) desc
I'm well confused, what I'm doing wrong?
This query, you assert that followalbe_id is equal to 'place_lists.id'.
->orderByDesc(
Follow::query()->select('created_at')
->where('created_by_user_id', $userID)
->where('followable_id', 'place_lists.id')
)
To compare two columns use whereColumn() instead.
->orderByDesc(
Follow::query()->select('created_at')
->where('created_by_user_id', $userID)
->whereColumn('followable_id', 'place_lists.id')
)
I'm not sure if I'm on the right track here but in line 9 of your eloquent builder the query generated will use a string to compare followable_id against and therefore look like this:
and `followable_id` = 'place_lists.id'
Using DB::raw() in your where-clause in line 9 should fix that:
$myQuery = PlaceList::query()
->where('private', 0)
->whereHas('followers', function ($query) use ($userID) {
$query->where('created_by_user_id', $userID);
})
->orderByDesc(
Follow::query()->select('created_at')
->where('created_by_user_id', $userID)
->where('followable_id', DB::raw('`place_lists`.`id`')) // here
)
->get()

Laravel raw select with avg - cannot display fetched data

I have Laravel project and I want to fetch avg time. Select statement is correct but I can not display data because I get error: Array to string conversion
This is my code:
$limit = (int)$this->argument('distance');
$avgTimeBetweenBlocks = DB::select('SELECT AVG(b.timediff)
FROM
(
SELECT a.created_at, a.created_at_end, AVG(TIME_TO_SEC(TIMEDIFF(a.created_at, a.created_at_end))) AS timediff
FROM
(
SELECT created_at,
(
SELECT max( created_at)
FROM block_differences bd1
WHERE bd1.created_at < bd.created_at
) as created_at_end
FROM block_differences bd
limit :limit
) a
WHERE a.created_at_end is not null
GROUP BY a.created_at, a.created_at_end
) b', ['limit' => $limit] )->get();
echo json_decode(json_encode($avgTimeBetweenBlocks[0]), true);
$this->info("avgTimeBetweenBlocks {$avgTimeBetweenBlocks[0]} seconds");
I tried to display value in different way, but all the time I get the same result.
You're trying to echo an array here json_decode will convert it an array so echo will not work. use print_r instead of echo
print_r(json_decode(json_encode($avgTimeBetweenBlocks[0]), true));
Edit :- Array ( [AVG(b.timediff)] => 139.38775510 )
you've to change your query. check here I give you an example below.
$avgTimeBetweenBlocks = DB::select('SELECT AVG(b.timediff) as avgtimediff
FROM
(
SELECT a.created_at, a.created_at_end, AVG(TIME_TO_SEC(TIMEDIFF(a.created_at, a.created_at_end))) AS timediff
FROM
(
SELECT created_at,
(
SELECT max( created_at)
FROM block_differences bd1
WHERE bd1.created_at < bd.created_at
) as created_at_end
FROM block_differences bd
limit :limit
) a
WHERE a.created_at_end is not null
GROUP BY a.created_at, a.created_at_end
) b', ['limit' => $limit] )->get();
$response = json_decode(json_encode($avgTimeBetweenBlocks[0]), true);
echo $response['avgtimediff'];

List all 'feeds' and only 2 users with relationship

I need to make a list of all the items in the table feed and show only the first 2 users who subscribe to the content, but I can not put together a query that does the list only 2 users limit 2.
I've tried N querys and subquery, but could not get the expected result. The nearest was using group_concat, but if it concatenates all users and does not allow limited only to two initial, and would have to usesubstring_index for this purpose.
Query
select
feed.id
, feed.type
, user.name
from feed
inner join user on user.id = feed.user
group by feed.type
Result
Array(
[0] => Array(
[id] => 1
[type] => Comedy
[name] => Mike
)
[1] => Array(
[id] => 3
[type] => War
[name] => John
)
[2] => Array(
[id] => 6
[type] => Terror
[name] => Sophia
)
)
Expected
Array(
[0] => Array(
[id] => 1
[type] => Comedy
[name] => Mike, Papa
)
[1] => Array(
[id] => 3
[type] => War
[name] => John, Alex
)
[2] => Array(
[id] => 6
[type] => Terror
[name] => Sophia, Jessica
)
)
set #rn=0;
select id, type, name
from
(
select
#rn:=#rn+1 AS r_n
,feed.id
,feed.type
,user.name
from feed
inner join user on user.id = feed.user
group by feed.id
order by feed.id) t
where t.r_n <= 2
You can generate row numbers per group and then select the first 2 rows per feed id.
I don't know exactly the schema of your tables but try the same approach you already tried with group_concat but join to a subquery like:
...
inner join
(
select user.id, user.name from user limit 2
) as x on x.id = feed.user
...
You can use variables to simulate row_number() to give each user per feed a "rank" and only select rows with number <= 2 before doing the grouping in order to only get 2 users per group:
select id, type, group_concat(name) from (
select * from (
select *, #rn := if(#prevFeedId = id, #rn+1, 1) as rn,
#prevFeedId := id
from (
select
feed.id
, feed.type
, user.name
from feed
inner join user on user.id = feed.user
) t1 order by id
) t1 where rn <= 2
) t1 group by id, type

How to use $wpdb->prepare with WHERE NOT EXISTS to prevent duplicate entry

In WordPress Development Stack Exchange, I answered my own Question where I mentioned that, with the following code I'm able to insert data into database, but can prevent duplicate entries:
INSERT INTO {$wpdb->prefix}user_req
( user_id, post_id )
VALUES ( %d, %d )
WHERE NOT EXISTS (
SELECT * FROM
{$wpdb->prefix}user_req.user_id = user_id
AND
{$wpdb->prefix}user_req.post_id = post_id
)
I don't know why, it's actually NOT working (I don't know how it worked that time!!). Now I modified my code into this:
$wpdb->query( $wpdb->prepare(
"
INSERT INTO {$wpdb->prefix}user_req
( user_id, post_id )
VALUES ( %d, %d )
WHERE NOT EXISTS (
SELECT *
FROM
{$wpdb->prefix}user_req
WHERE
{$wpdb->prefix}user_req.user_id = VALUES({$user_id})
AND
{$wpdb->prefix}user_req.post_id = VALUES({$post_id[1]})
)
",
$user_id,
$post_id[1]
) );
But still it's not working, even it's failing to insert the data into db.
What am I missing?
It is not allowed to use a where clause with insert ... values .... Try using insert ... select ... where ... instead:
INSERT INTO
{$wpdb->prefix}user_req (
user_id,
post_id
)
SELECT
%d,
%d
FROM
DUAL
WHERE
NOT EXISTS (
SELECT
0
FROM
{$wpdb->prefix}user_req
WHERE
{$wpdb->prefix}user_req.user_id = user_id
AND
{$wpdb->prefix}user_req.post_id = post_id
)
$wpdb->query( $wpdb->prepare(
"
INSERT INTO {$wpdb->prefix}user_req
( user_id, post_id )
VALUES ( %d, %d )
WHERE 0 = (
SELECT count(*)
FROM
{$wpdb->prefix}user_req
WHERE
{$wpdb->prefix}user_req.user_id = VALUES({$user_id})
AND
{$wpdb->prefix}user_req.post_id = VALUES({$post_id[1]})
)
",
$user_id,
$post_id[1]
) );
There are a couple of issues - first using INSERT/SELECT utilizing the DUAL dummy table name is recommended (only returning the values when the result of the subquery is 0), however to properly execute the subquery you will need to pass your parameters in twice. Using a table alias can make things easier to manage. See the example below.
// Set up your query using HEREDOC format
$sql = <<<SQL
INSERT INTO {$wpdb->prefix}user_req
( user_id, post_id )
SELECT %d, %d
FROM DUAL
WHERE 0 = (
SELECT COUNT(*)
FROM {$wpdb->prefix}user_req AS ur
WHERE ur.user_id = %d
AND ur.post_id = %d
SQL;
// Call prepare(), pass values first for INSERT, and again for the sub SELECT
$sql = $wpdb->prepare( $sql, $user_id, $post_id[1], $user_id, $post_id[1] );
// Execute the query
$wpdb->query( $sql );
Ok, I did it at last with two different queries - I agree, not a smarter one, but at least solved my one, as all the other possibilities are a mixture of two queries:
$alreadyGot = $wpdb->get_results(
"SELECT
COUNT(*) AS TOTALCOUNT
FROM {$table}
WHERE ( user_id = $user_id AND post_id = $post_id[1] )
AND ( order_id = '' )"
);
$count = $alreadyGot[0]->TOTALCOUNT;
if( $count > 0 ) {
//do nothing
} else {
$wpdb->insert(
$table,
array(
'user_id' => $user_id,
'post_id' => $post_id[1]
)
);
}
Thanks to my colleague Mr. Ariful Haque.

Fetching 10 items each of child table in mysql

I have a table categories (id, cat_name) and a table recipes (id, cat_id, recipe_text).
Now I want to write a query, that fetches from each category 10 recipes.
SELECT cat_name, recipe_text
FROM categories c
JOIN recipes r ON c.id=r.cat_id
would fetch ALL recipes, but I want a maximum of 10 recipes per category.
(How) could it be done with a SQL-Query?
Taken from mySQL Returning the top 5 of each category:
SELECT cat_name, recipe_text
FROM
(
SELECT c.cat_name AS cat_name, r.recipe_text AS recipe_text,
#r:=case when #g=c.id then #r+1 else 1 end r,
#g:=c.id
FROM (select #g:=null,#r:=0) n
CROSS JOIN categories c
JOIN recipes r ON c.id = r.cat_id
) X
WHERE r <= 10
You may try the below code
function recipe($cat_id='',$new_ar=array())
{
if($cat_id!="")
{
$new_ar1=array();
$db="select recipe_text from recipes where cat_id=".$cat_id." order by cat_id limit 10";
$sq=mysql_query($db);
while($fe=mysql_fetch_object($sq))
{
array_push($new_ar1,$fe->recipe_text);
}
return $new_ar1;
}
else
{
$db="select id,cat_name from categories order by id";
$sq=mysql_query($db);
while($fe=mysql_fetch_object($sq))
{
array_push($new_ar,$fe->cat_name);
$new_ar[$fe->id]=array($fe->cat_name);
array_push($new_ar[$fe->id],recipe($fe->id,$new_ar));
}
}
}
recipe();
it will give output like below
Array
(
[0] => cat 1
[1] => Array
(
[0] => cat 1
[1] => Array
(
[0] => rice
[1] => curry
[2] => mutton
[3] => A recipe
[4] => B recipe
[5] => C recipe
[6] => D recipe
[7] => E recipe
[8] => F recipe
[9] => G recipe
)
)
[2] => Array
(
[0] => cat 2
[1] => Array
(
[0] => dal
[1] => fish
)
)
[3] => Array
(
[0] => cat 3
[1] => Array
(
)
)
[4] => Array
(
[0] => cat 4
[1] => Array
(
)
)
)
Thanks
Ripa Saha
this will do for u...
SET #rank = 0;
SELECT cat_name,recipe_text FROM (SELECT
id,cat_id AS P,recipe_text,
CASE
WHEN #rowdata != pid
THEN #rank := 0 & #rowdata := cat_id
ELSE #rank := #rank + 1
END AS rank
FROM
recipes
GROUP BY cat_id,
id
) X ,t
WHERE X.rank <= 3 AND X.p = t.cat_id;
Try below SQL
select
cat_name,
recipe_text
from categories as c,recipes as r
where c.id=r.cat_id limit 10
We finally made a stored procedure:
DELIMITER $$
CREATE PROCEDURE `test`()
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE cur_id INT;
DECLARE cur CURSOR FOR
SELECT id FROM category;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
CREATE TABLE tmp(catname VARCHAR(255), recipeId INT);
OPEN cur;
the_loop: LOOP
FETCH cur INTO cur_id;
IF done THEN
LEAVE the_loop;
END IF;
INSERT INTO tmp(catname, recipeId)
SELECT catname, recipeId
FROM category c LEFT JOIN recipes r ON c.id=r.cat_Id
WHERE c.id=cur_id
LIMIT 0, 10;
END LOOP;
SELECT * FROM tmp;
DROP TABLE tmp;
END
SET #num :=0, #cat_id := '';
SELECT recipe_text,cat_name,
#num := if(#cat_id = cat_id, #num + 1, 1) as row_number,
#cat_id := cat_id as cat_id
FROM recipes r
JOIN categories c ON c.id = r.cat_id
group by cat_name,recipe_text
having row_number <= 10