Aggregating queries by maximum count (MYSQL) - php

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

Related

MySQL get earliest row by type and status where type order is from array

i want to get earlest row that has status 0 but for type column is sorted by array, for example, I have array like below
$myArray = ['checkerA', 'detailMaker', 'checkerB', 'checkerD', 'checkerC']
And then I have table look like below. as you can see the order of data in the column type is 'CheckerC' first and then 'checkerD', but I want to get row based on my Array
id
name
type
status
5
sit
checkerD
0
4
Dolor
checkerC
0
3
Ipsum
checkerB
1
2
Lorem
detailMaker
1
1
John doe
checkerA
1
Here's my query that I have made. (btw I only want to get the id data)
SELECT MIN(CASE WHEN status = 0 THEN id END) FROM myTable
If I use that code, I'll get CheckerC, which is where my expectation is I want to get CheckereD.id
Is there any way that I can implement my array into the query? Thanks
You can use this query to get the row with status 0 and get the earliest entry
SELECT * FROM myTable where status =0 order by id asc LIMIT 1 OFFSET 0

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

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.

MySQL: standard approach VS set-based approach for multi-row results

Following up on this question, there is problem with the standard approach or a recursive approach in the case below.
For instance, I want to return the page with the same parent_id and some pages have multiple row contents,
page table
page_id page_title parent_id
1 a 1
2 aa 1
3 ab 1
4 ac 1
content table
content_id content_text
1 text one
2 text two
3 text one aa
4 text two aa
5 text one ab
6 text one ac
content structure table
page_id content_id order_in_page
1 1 1
1 2 2
2 3 1
2 4 2
3 5 1
4 6 1
The standard approach,
SELECT
p.*,
c.*,
x.*
FROM pages AS p
LEFT JOIN pages_structures AS x
ON x.page_id = p.page_id
LEFT JOIN pages_contents AS c
ON c.content_id = x.content_id
WHERE p.parent_id = '1'
AND p.page_id != '1'
result (it lists the row as 4 items),
page_id page_title parent_id content_text order_in_page
2 aa 1 text one aa 1
2 aa 1 text two aa 2
3 ab 1 text one ab 1
4 ac 1 text one ac 1
As you can notice that there are two rows with page_id 2 and one row for each 3 and 4. How do you display the data into HTML with the standard approach like below (as suggested in one of the answer in the previous question)?
echo $page[0]['page_title'];
echo $page[0]['content_text'];
But with set-based one, I can do it with this,
SELECT
page_id,
page_title,
MAX(IF(order_in_page = 1, content_text, NULL)) AS content_1,
MAX(IF(order_in_page = 2, content_text, NULL)) AS content_2,
.
.
.
FROM
pages AS p LEFT JOIN
pages_structures AS x ON x.page_id = p.page_id LEFT JOIN
pages_contents AS c ON c.content_id = x.content_id
WHERE
p.parent_id = '1'
AND
p.page_id != '1'
GROUP BY page_id
in PHP,
foreach($items as $item)
{
echo '<li><h3>'.$item['page_title'].'</h3>';
echo '<p>'.$item['content_1'].'</p>';
echo '<p>'.$item['content_2'].'</p></li>';
}
the HTML (it lists the row as 3 items which is correct),
<li>
<h3>aa</h3>
<p>text one aa</p>
<p>text two aa</p>
</li>
<li>
<h3>ab</h3>
<p>text one ab</p>
<p></p>
</li>
<li>
<h3>ac</h3>
<p>text one ac</p>
<p></p>
</li>
Hope this makes sense!
with the standard approach you just keep track of the current page in a variable, and when the page changes, you roll to a new list item.

Categories