Laravel raw select with avg - cannot display fetched data - mysql

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'];

Related

Get 2 Previous and Next with Current entry from database in laravel

I'm showing the image on a page. I am getting data with this
$designs = Design::take(10)->where('show', '1')->where('id', $id)->orderBy('hit', 'desc')->get();
Now I want 2 previous and 2 next records so users can select and see them.
Something like
Select 5 entry where the middle should be 'id'
The solution I came up with is the following:
You find the middle design.
Using it's id, you can get the previous 2 and make an union with a similar query that gets the next 2 (along with the original).
$design = Design::select('id')
->where('name', 'Sunset')
->firstOrFail();
$designs = Design::query()
->where('id', '<', $design->id)
->orderByDesc('id')
->limit(2)
->union(
Design::query()
->where('id', '>=', $design->id)
->orderBy('id')
->limit(3)
)
->orderBy('id')
->get();
The SQLs generated by this query are the following:
SELECT `id` FROM `designs`
WHERE `name` = "Sunset"
LIMIT 1
(
SELECT * FROM `designs`
WHERE `id` < ?
ORDER BY `id` DESC
LIMIT 2
)
UNION
(
SELECT * FROM `designs`
WHERE `id` >= ?
ORDER BY `id` ASC
LIMIT 3
)
ORDER BY `id` ASC
... Or if you'd rather have the results more separated
$design = Design::where('name', 'Sunset-Image')->firstOrFail();
$previous = Design::where('id', '<', $design->id)->orderByDesc('id')->limit(2)->get();
$next = Design::where('id', '>', $design->id)->orderBy('id')->limit(2)->get();

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()

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

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)');

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.

Query two tables with mysql to count total topics by hour

my forum have two tables to store topics (posts and forums_archive_posts)
$this->DB->build( array(
'select' => "HOUR( FROM_UNIXTIME( post_date ) ) as hour, COUNT(*) AS postCount",
'from' => 'posts',
'where' => "new_topic=0 AND author_id=" . $member['member_id'],
'group' => 'HOUR( FROM_UNIXTIME( post_date ) )',
) );
This query works only with the first table (posts), I need a query that works also in "forum_archive_posts"
tables structure (forum_archive_posts=posts):
archive_author_id = author_id
archive_content_date = post_date
No idea of how you do it in that format but something like
Select postHour, sum(postcount) as postCount From
(
select Hour ... as PostHour
From
Posts...
Union
Select Hour ...
From
ForumArchivePosts ...
) dummyTableName
Group by PostHour
should do the job. the do count bny hoiurs from both tables, then add them together.