Getting a query result whiting a group by - php

I’m trying to get some result of a query. The table stock information about which page in a website visited by a user. So I can have in a row user that visit page "A" per example and a second row with the same user who visit the page "B". I want to do a query that select the user or users who visit the page "A" and "B". I can’t make a “and” in my where condition because there are just one column.
There is the table structure
ID | user_id | page | views
1 1 A 44
2 1 B 120
3 2 A 140
4 3 A 22
I have try this but doesn't work
SELECT users.name,users.id,users.email
FROM users
JOIN help_messages ON users.id = help_messages.id_user
WHERE (PAGE LIKE '%clubs%' or PAGE like '%profile%') and views >= 1
GROUP BY help_messages.id_user, help_messages.page
So any solutions please. Thanks

A general approach to this uses aggregation and a having clause:
select user_id
from table t
group by user_id
having sum(page = 'A') > 0 and sum(page = 'B') > 0;
The first condition in the having clause counts the number of rows that have an 'A' and only allows user_ids that have at least one such row. The second condition does the same for 'B'.
This is a general approach because it is easy to add additional pages. Also, if you want someone who visited 'A' but not 'B', you would just use:
having sum(page = 'A') > 0 and sum(page = 'B') = 0;

Related

Search Two Tables & Concatenate Answer

I am trying to search two tables, match the results and then concatenate the answer... Only finding results >= today's date. This will then give the user the option to delete the selected from the DB. So...
Table 1 called Prog_name
id prog_name
1 Breakfast
2 Mid Morning
3 Afternoon
Table 2 called talk_ups
id date_tx prog_name (prog_name value = prog_name.id)
1 2017-06-30 2
2 2017-07-03 1
3 2017-07-01 3
The result I am after is something like: "01-07-2017, Afternoon". But I do also need the talk_ups.id to ensure it only deletes the correct record.
I managed to figure out how to get the name to match the talk_ups.prog_name value:
'$sql. = "SELECT talk_ups.prog_name, prog_name.id as progID, prog_name.prog_name as theName FROM prog_name, talk_ups WHERE talk_ups.prog_name = prog_name.id";'
But I can't figure out how to do the two searches and end up with the right result and how to separate out the results to then concatenate them.
You can use JOIN with WHERE condition, e.g.:
SELECT pn.id, pn.prog_name, tu.date_tx
FROM prog_name pn JOIN talk_ups tu ON pn.id = tu.prog_name
WHERE tu.date_tx > NOW();

Complex MySQL Conversation Group Query?

I have the following tables.
conversations
| id |
------
1
and
conversationMembers
| id | conversationId | userId | email
---------------------------------------
1 1 2 null
2 1 null test#test.com
3 1 7 null
Basically, I'm trying to construct a MySQL query that returns a row from the conversations table by an exact match of conversationMembers.
So, here's some examples of expected returns.
Let's say we want a a conversation id for a conversation between the exact following members: userId 2, userId 7, email test#test.com - This would see that in the conversationMembers table there's rows with the same conversation id and the exact match across all members of that conversation id that we're searching for. It would return conversations row with id 1.
Here's another example. We want a conversation id for a conversation between userId 2 and userId 7. This would see that there's not a conversation exclusively between userId 2 and userId 7, so it would not return anything.
And a final example. Let's say we want userId 7 and userId 9, this would also see there's no exclusive conversation between these 2 user id's and would return nothing.
What's the best way to go about doing it? I've played with subqueries but everything I've come up with doesn't seem to be able to handle the exact matching situation - I was having issues with selecting conversations for example - on userId 2 and 7 only (which should return nothing) and was getting conversationId 1 back, even though I didn't specify I wanted a conversation with test#test.com email as a part of it. I should only have gotten conversationId 1 back for if I searched on an exact match of all members in for conversationId.
One method is to use group by and having. This is nice because it is flexible with regards to what can be expressed. So, your first example is:
select conversionid
from conversationMembers
group by conversionid
having sum(userId = 2) > 0 and
sum(userId = 7) > 0 and
sum(email = 'test#test.com') > 0;
The condition being summed counts the number of members that match. The > 0 means there is at least one. For the second condition, the clause would be:
having sum(userId = 2) > 0 and
sum(userId = 7) > 0 and
sum(userId not in (2, 7)) = 0;
or alternatively:
select conversionid
from conversationMembers
group by conversionid
having sum(userId = 2) > 0 and
sum(userId = 7) > 0 and
count(distinct userId) = 2;

MySQL count datas with row values without new query loop

I've 4 table for a newsletter. Newsletters, Subscribers, Subscriber Groups and Selected Subscriber Groups. I've choose subscriber groups in campaign edit area, and its save selected groups to tbl_newsletter_groups table like;
tbl_newsletters
NID title details
1 text 1 content 1
2 text 2 content 2
tbl_subscriber_groups
GID group_name
5 group 1
6 group 2
tbl_subscribers
SID GID email name
10 5 sub1#mail.com sub1 name
11 6 sub1#mail.com sub1 name
tbl_newsletter_groups
NGID NID GID
15 1 6
16 1 6
17 1 6
I want to show total selected subscriber count when I list newsletters in my page. My soulution works fine, Im looking for simple and clearly statement, there any faster way available like in single newsletter list statement?
Here my own count style (yes I know its too bad and long way);
$subGID = array();
$list = $myconn->query("SELECT * FROM tbl_newsletters");
while($listRs = $list->fetch_assoc()){
$grps = $myconn->query("SELECT * FROM tbl_newsletter_groups WHERE NID=". $listRs['NID'] ."");
while($grpsRs = $grps->fetch_asscoc()){
$subGID[] = $grpsRs['GID'];
} $grps->free();
$subs = implode(" OR GID=",$subGID);
$count = mysqli_num_rows($myconn->query("SELECT ID FROM tbl_subscribers WHERE GID=". $subs));
echo('Total Selected Subscriber: '.$count);
} $list->free();
Thanks.
The search term you want is "set-based logic".
Your thinking is sound: you need everything from tbl_newsletters, then you need to count results from tbl_subscribers, but in order to get those you need information from tbl_newsletter_groups.
In SQL, that's an indication you want a join. You've already discovered the conditions you need, you just don't know the syntax. A reference manual can help there.
Now you'll have a bunch of records, which you need to smash into a smaller number of records. You need aggregation functions and a GROUP BY clause.
So here's the final query:
SELECT n.NID, n.title, n.details, COUNT(s.SID)
FROM tbl_newsletters AS n
JOIN tbl_newsletter_groups AS g ON n.NID = g.NID
JOIN tbl_subscribers AS s ON g.GID = s.GID
GROUP BY n.NID

php pdo copy column between tables

I got the two tables(Table1 and Table2):
Table1:
id hits url
1 11 a
2 5 b
3 6 c
4 99 d
5 14 e
Table2:
id url 2014.04.13 2014.04.14
1 a 0 5
2 b 0 1
3 c 0 3
4 d 0 60
5 e 0 10
hi all,
Table1 one contains the actual hits(which are always up-to-date) and Table2 to statistics(which are done every day at midnight). The columns id(unique number) and url are in both tables the same. So they got the same amount of rows.
So i create every day a new column(with the date of today) and copy the column hits from the table 'Table1' into the new created column into the table 'Table2'
First i alter Table2:
$st = $pdo->prepare("ALTER TABLE Table2 ADD `$today_date` INT(4) NOT NULL");
$st->execute();
Then i cache all entries i need from Table1:
$c = 0;
$id = array();
$hits = array();
$sql = "SELECT id, hits FROM Table1 ORDER BY id ASC";
$stmt = $pdo->query($sql);
while($row = $stmt->fetch(PDO::FETCH_ASSOC))
{
$id[$c] = $row['id'];
$hits[$c] = $row['hits'];
$c++;
}
At last i update Table2:
for ($d = 0 ; $d < $c ; $d++)
{
$id_insert = $id[$d];
$sql = "UPDATE DOWNLOADS_TEST SET `$datum_det_dwnloads`=? WHERE id=?";
$q = $pdo->prepare($sql);
$q->execute(array($hits[$d], $id[$d]));
if($q->rowCount() == 1 or $hits[$d] == 0) // success
$hits[$d] = 0;
else // error inserting (e.g. index not found)
$d_error = 1; // error :( //
}
So what i need is to copy(insert) a column from one table to another.
The two tables are having ~2000 elements and the copying as described above takes around 40 sec. The bottleneck is the last part (inserting into the Table2) as i found out.
One thing i found is to do multiple updates in one query. Is there anything i can do besides that?
I hope you realise that at some point your table will have irrational number of columns and will be highly inefficent. I strongly advise you to use other solution, for example another table that holds data for each row for each day.
Let's say you have a table with 2000 rows and two columns: ID and URL. Now you want to know the count of hits for each URL so you add column HITS. But then you realise you will need to know the count of hits for each URL for every date, so your best bet is to split the tables. At this moment you have one table:
Table A (A_ID, URL, HITS)
Now remove HITS from Table A and create Table B with ID and HITS attributes). Now you have:
Table A (A_ID, URL)
Table B (B_ID, HITS)
Next move is to connect those two tables:
Table A (A_ID, URL)
Table B (B_ID, A_ID, HITS)
Where A_ID is foreign key to attribute "A_ID" of Table A. In the end it's the same as first step. But now it's easy to add date attribute to Table B:
Table A (A_ID, URL)
Table B (B_ID, A_ID, HITS, DATE)
And you have your solution for database structure. You will have a lot of entries in table B, but it's still better than a lot of columns. Example of how it would look like:
Table A | A_ID | URL
0 index
1 contact
Table B | B_ID | A_ID | HITS | DATE
0 0 23 12.04.2013
1 1 12 12.04.2013
2 0 219 13.04.2013
3 1 99 13.04.2013
You can also make unique index of A_ID and DATE in Table B, but I prefer to work on IDs even on linking tables.

Find related posts and rank them by relevance

I have a website with different articles. The database structure is like this:
ArticleId | ArticleLocation | ArticleCategory | ArticleTopic
The actual text strings for the columns are in another table so all the columns are populated with numbers (integers)
I want to find related posts, meaning if a user reads an article with ArticleLocation = 1, ArticleCategory= 3 and ArticleTopic = 2, then I want to find top 5 of articles sharing the most of the same column values.
Any ideas of how to do this?
Thanks in advance
Assuming the table is named ArticleTable, try the following:
SELECT *, (
CASE ArticleLocation WHEN :loc THEN 1 ELSE 0 END +
CASE ArticleTopic WHEN :topic THEN 1 ELSE 0 END +
CASE ArticleCategory WHEN :cat THEN 1 ELSE 0 END) AS Relevance
FROM ArticleTable
ORDER BY Relevance DESC
LIMIT 5
with :loc, :topic and :cat set to the relevant values.

Categories