Laravel query - grouping results in a range of dates - php

I have a table from which I'd like to pull a list of object_id that satisfy condition:
extended_data starts with "Text1" or "Text2",
time difference between records in table containing "Text1" and "Text2" for a given object_id is less than 2 seconds.
I'm sending code written so far and an example table with selected records that meet condition. As a result, the query for example should return [3, 7].
How should I expand code to get solution?
id
object_id
extended_data
timestamp
1
1
Text1 lorem
12.01.2023 11:01:22
2
2
Text2 lorem
12.01.2023 11:02:25
3
3
Text1 lorem
12.01.2023 11:03:04
4
3
Text2 lorem
12.01.2023 11:03:05
5
4
Lorem
12.01.2023 11:05:44
6
5
Text1 ipsum
12.01.2023 11:05:45
7
null
ipsum
12.01.2023 11:06:23
8
6
Text1 ipsum
12.01.2023 11:08:21
9
6
Text2 ipsum
12.01.2023 11:08:32
10
7
Text1 ipsum
12.01.2023 11:09:12
11
7
ipsum
12.01.2023 11:09:12
12
7
Text2 ipsum
12.01.2023 11:09:12
$logs = Logs::whereNotNull('object_id')->get();
$filtered = $logs->filter(function (Logs $log) {
return str_starts_with($log->extended_data, "Text1") || str_starts_with($log->extended_data, "Text2");
})->values();
foreach ($filtered as $index => $log) {
$unset = false;
$actualTimestamp = strtotime($log->timestamp);
if ($index > 0) {
$previousTimestamp = strtotime($filtered[$index - 1]->timestamp);
$differenceInSeconds = $actualTimestamp - $previousTimestamp;
if ($differenceInSeconds > 2) {
$unset = true;
}
}
if (count($filtered) - 1 > $index) {
$nextTimestamp = strtotime($filtered[$index + 1]->timestamp);
$differenceInSeconds = $nextTimestamp - $actualTimestamp;
if ($differenceInSeconds > 2) {
$unset = true;
}
}
if ($unset) {
$log->unset = true;
}
}
foreach ($filtered as $index => $log) {
if (isset($log->unset) && $log->unset) {
unset($filtered[$index]);
}
}

I have written this assuming that the timestamp column contains a valid datetime/timestamp (2023-01-12 11:01:22) and not the string format (12.01.2023 11:01:22) you have included in your sample data.
SELECT l1.object_id
FROM logs l1
JOIN logs l2
ON l1.object_id = l2.object_id
AND l2.extended_data LIKE 'Text2%'
AND l2.timestamp BETWEEN l1.timestamp AND l1.timestamp + INTERVAL 2 SECOND
WHERE l1.extended_data LIKE 'Text1%'
And, assuming the text of this query is static, to run it you can just do -
$logs = DB::select("
SELECT l1.object_id
FROM logs l1
JOIN logs l2
ON l1.object_id = l2.object_id
AND l2.extended_data LIKE 'Text2%'
AND l2.timestamp BETWEEN l1.timestamp AND l1.timestamp + INTERVAL 2 SECOND
WHERE l1.extended_data LIKE 'Text1%'
");
There would be no benefit in building up this query using Query Builder.

Related

How to use if else condition with Join in php

I want to fetch questions of $id(dynamic,passing as parameter) and want to whether this is
"ParentbusinessId" or "businessId"
table name "nps_ques"
id config_id question
1 1 Lorem Ipsum
2 1 Lorem Ipsum2
3 1 Lorem Ipsum3
Table "nps_config"
id parentBusinessId businessId
1 4580 NULL
2 0 2
3 4580 3
I tried with following code
$this->db->select('nq.id as ques_id,nq.config_id as formId,nq.question,nc.parentBusinessId,nc.businessId)
->from('nps_ques nq')
->join("nps_config nc", "nc.id=nq.config_id")
->where("nq.config_id", $id)
->order_by("nq.id", "ASC");
You can use CASE.
See example below:
SELECT
config.id AS config_id,
questions.question,
case when config.parent_business_id is not null then config.parent_business_id else config.business_id end as business
FROM
questions
JOIN
config ON questions.config_id = config.id
WHERE
config.id = 1;

mysqlCount not working with join,Showing wrong result

I have two tables"shopinfo" and "rating" and i am trying to count review with Join but showing me wrong result
Here is my first table "shopInfo"
id shopOpen shopname
1 2 abc
2 1 xyz
3 2 dnu
4 2 rfy
Here is my table "rating"
id shopId rating review
1 2 3 Lorem Ipsum
2 2 4 Lorem Ipsum
3 4 5 Lorem Ipsum
4 2 1 Lorem Ipsum
And here is my code which showing me wrong result in review count (showing me 6 , should be 3),
Where i am wrong ?
SELECT si.shopOpen, COUNT(r.review) as reviewCount, AVG(r.rating) AS AvgRating
FROM shopInfo si
LEFT JOIN rating r ON r.shopId=si.id
WHERE si.shopId = '2'
you are missing group by. when you use aggregated functions like sum(), avg() you have to group by non-aggregated column. In your case it is si.shopOpen
Here is the fiddle link provided by #VBoka
SELECT
si.shopOpen,
COUNT(r.review) as reviewCount,
AVG(r.rating) AS AvgRating
FROM shopInfo si
JOIN rating r ON r.shopId=si.id
WHERE si.shopId = '2'
group by
si.shopOpen

result not getting using multidimensional array

The tool_id given here are 7 and 5 and the quantity selected are 3 and 2 respectively.When i select the tool_id of 7 i need to get changed quantity of that tool_id to 3 and when i select the tool_id of 5 i need to get changed quantity of that tool_id to 2.need to change as per the id selected please help me to solve my problem
Here is my code
$tool_id = array(7,5); //array of id
$quantity = array(3,2);//array or qty
$updateArray = array();
for($x = 0; $x < count($tool_id); $x++){
$updateArray[] = array(
'id'=>$tool_id[$x],
'available' => $quantity[$x]
);
}
$this->db->update_batch('tbl_tools',$updateArray,'id');
please help me to solve my problem
public function edit_available()
{
$tool_id=array(7,5);
var_dump($tool_id);
$quantity=array(3,2);
var_dump($quantity);
$data = array();
$i = 0;
foreach($tool_id as $t){
$data[$i]['id'] = $t;
$data[$i]['available'] = $quantity[$i];
$i++;
}
$query=$this->db->update_batch('tbl_tools', $data, 'id');
var_dump($query);
if($query)
{
return true;
}
else
{
return false;
}
}
here am having two tables namely tbl_tools and tbl_tool_use.
the tbl_tools looks as follows
id name quantity available type
5 cutting player 5 5 engineer
6 reflectors 2 2 team
7 spanner 8 8 engineer
8 tester 4 4 team
tbl_tool_use looks as follows
id user_id type tool_id quantity available start_date end_date
201 26 engineer 7,5 3,2 8available,5available 2016-12-30
here in the table tbl_tool_use the tool_id selected are 7 and 5 and for that the quantity selected are 3 and 2 respectively while inserting this data in to the this table at the same time my tbl_tools table should get reduced like this
id name quantity available type
5 cutting player 5 2 engineer
6 reflectors 2 2 team
7 spanner 8 3 engineer
8 tester 4 4 team
this is the concept for that am using that code
Here is your solution.
$tool_id = array(7,5); //array of id
$quantity = array(3,2);//array or qty
$arrayCombine = array_combine($tool_id, $quantity);
// var_dump($arrayCombine);
foreach ($arrayCombine as $key => $value) {
$updateArray[] = array(
'id'=>$key,
'available' => $value
);
}
$this->db->update_batch('tbl_tools',$updateArray,'id');

Aggregating queries by maximum count (MYSQL)

I have a follow table like so:
id eventid user
1 1 ABC
2 4 XYZ
3 4 DEF
4 1 XYZ
5 1 DEF
And an event table like so:
eventid title desc
1 tuv Lorem Ipsum
2 yfc Lorem Ipsum
3 jhk Lorem Ipsum
4 lmn Lorem Ipsum
I want a query that would output the list of popular events based ordered by the highest number of followers of that event.
For ecample, eventid 1 has the highest number of followers so that will be listed first and second will be event with eventid=4
select t1.eventid,t1.count(t1.eventid) as count_followers
from table_name t1 inner join events_table t2
on t1.eventid=t2.eventid group by t1.eventid order by count_followers desc

How do I efficiently find and keep a log of duplicate tweets in my database?

Please consider the following "tweets" table:
tweet_id user_id text
----------------------------
1 1 lorem ipsum
2 1 lorem ipsum
3 2 pear
4 1 dolor
5 3 foo
6 1 dolor
7 1 dolor
8 3 bar
9 3 baz
10 4 happy
11 4 happy
12 2 apple
13 3 foo
14 4 happy
In reality, the table contains millions of tweets from about 80,000 users. Many of there users are spam accounts, but they are hard to identify by hand. As a rule of thumb, spam accounts post the same message at least 3 times. That's why I want to fill the following tables, "duplicates" on the left and "duplicates_tweets" on the right:
duplicate_id user_id text cnt duplicate_id tweet_id
-------------------------------------- ----------------------
1 1 lorem ipsum 2 1 1
2 1 dolor 3 1 2
3 2 pear 1 2 4
4 2 apple 1 2 6
5 3 foo 2 2 7
6 3 bar 1 3 3
7 3 baz 1 4 12
8 4 happy 3 5 5
5 13
6 8
7 9
8 10
8 11
8 14
I can now very easily sort on cnt for instance, and see which users post the most duplicate messages. My question however, is how to go about this most efficiently. In other words: what query would be most efficient to fill these tables? And is it possible with just SQL or should I use PHP as an intermediary, for instance to take a tweet from the "tweets" database, scans for duplicates, fills the tables, and moves on to the next tweet? I'm afraid this would take ages to finish, so any help is greatly appreciated!
Probably, you could sort the table "tweets" by user_id and then by text:
SELECT * FROM tweets ORDER BY user_id DESC, text DESC
Afterwards you can iterate over the results in PHP:
<?php
// ...
$lastuser = -1;
$lasttext = "";
$ids = array();
while ($row = mysql_fetch_assoc($result)) {
if($row['user_id'] != $lastuser || $row['text'] != $lasttext) {
$ids = array();
}
$ids[] = $row['id'];
if(count($ids) >= 3) {
// flag items as spam
}
$lastuser = $row['user_id'];
$lasttext = $row['text'];
}
?>
If you use indexes in your MySQL database, you should be able to process N tweets in approximately N*log(N).
You can use the REPLACE function in MySQL to UPDATE or INSERT a new row based on the key:
REPLACE duplicates
SELECT user_id, text
FROM (SELECT user_id, text, count(1) as count
FROM tweets
GROUP BY user_id, text
HAVING count(1) > 2))
I agree with what #MichaelRushton and #Kosta answered but I am wondering if you shouldn't need another table at all? If you build the query, you can ask the first table for the knowledge you are seeking. I especially like the trigger.
Do you just want to pull out a list of possible spam tweets? Try this:
SELECT
user_id,
text,
COUNT(DISTINCT tweet_id)
FROM
tweets
GROUP BY
user_id,
text
HAVING
COUNT(DISTINCT tweet_id) >= 3
You can then use PHP to iterate over the result and INSERT/UPDATE a duplicate_tweets table (although as Chris K mentioned, do you really need a duplicate_tweets table when you can just use this query?).
Before you insert new tweet, check tweets table whether such tweet already exists. If so, insert tweet and insert it in duplicates and duplicates_tweets tables. Or use triggers on insert for tweets table.

Categories