Select users with more than one instance in database - php

I have a table with a userID field and an itemID field. I would like to select all of those users that have two or more instances where itemID is the same (that is, if for example there are 3 records where userID = 1 and itemID = 7 then I would like those results, but not if there's just one instance). I need to get all users (not just results for a certain userID).
Can anybody suggest how I could do this?
Thanks.

You can do this using aggregation and a having clause. If you just want the users:
select distinct userID
from t
group by userId, itemID
having count(*) >= 2;
This is an interesting query because it is one of the very rare situations where group by and select distinct are used together. If you wanted the userId/itemId pairs, then you would use select userId, itemId, without the distinct.

You just need to use group by and having. The having clause is like where except that it also works on aggregations. So it's something like select userID, itemID, count(*) from mytable group by userID, itemID having count(*) > 1.

Related

query group by with order by

i need to create query with group by and order by, and i dont know how to do it.
query should return one record for the newest date for existing device_serial_number. enter image description here
so i would to get id 591 nad 592
solution can be in sql or the best way it will be in symfony, through query builder etc.
There are many ways to accomplish what you want.
First Way
The oldest way to select first, best, worst, whatever within a group is with a correlated subquery:
Select * from mytable outer
Where created_at = (
Select max(created_at)
from mytable inner
Where inner.device_serial_number = outer.device_serial_number
)
Second Way
Use a subselect to find earliest dates for all devices, them join back to the original table to filter:
Select a.*
From mytable a Inner Join
(Select device_serial_number, max(created_at) as latedate
From mytable b
Group By device_serial_number
) b
On a.device_serial_number=b.device_serial_number
And a.created_at=b.latedate
Third way
Use a window function to rank order all the dates and then pick the number one ranking.
Select * From (
Select *
, rank() Over (Partition By device_serial_number Order by created_at desc) as myrank
From mytable
)
Where myrank=1
Notice that while these 3 solutions use different aspects of SQL, they all have a common analytical approach. They are all two step processes whose first (inner) part involves finding the most recent created_at date for each device_serial_number and then reapplying that result back to the original table in the second (outer) part.

SQL: Delete duplicated rows? (PHP)

I have the following database and want to delete the red ones because they are doubouled. So I have to check every row if another row is matching by pid, price, price_old, link and shop.
But how can I check that and how can I delete it then?
Maybe an easier way would be to generate a id from the values inside each row. So if the values inside a row would be equal also the id would be equal and who have only one value to compare with the other id's.
Is that a better way? - If yes, how can I do that?
Greetings!
Do the fact you have no way for get thi distinct row you could add uniqie id using
ALTER TABLE my_table
ADD id int NOT NULL AUTO_INCREMENT
Once done you could use not in where the id are not the min grouped by the value you need for define the duplication
delete from my_table
where id NOT in ( select min(id) from my_table
group by shop, link
)
The simplest way is to run a distinct query:
select distinct pid, price, price_old, link, shop
from t;
You can create a new table using into. That is the simplest way. Because all columns are the same, MySQL doesn't offer a simple method to delete duplicate rows (while leaving one of them).
However, it is possible that your current results are generated by a query. If so, you can just add select distinct to the query. However, it would be better to fix the query so it doesn't generate duplicates. If this is the case, then ask another question with sample data, desired results (as text, not an image), and the query you are currently using.
Test this first on a test table:
DELETE t1
FROM t t1, t t2
WHERE t1.id > t2.id AND t1.price = t2.price
AND t1.link = t2.link AND t1.shop = t2.shop
AND t1.price_old = t2.price_old;
Basically you are removing the one with the highest ID if those parameters are equal
select * from
(select pid, price, price_old, link ,
row_number() over(partition by pid, price, price_old, link, shop order by pid) as rank
from my_table) temp
where temp.rank = 1
This Query will group by all the columns first and rank them. Duplicate rows will have rank > 1. It does not matter we take first or second row as both are copy of each other. We just take rows with rank 1. Rows that are not duplicate will also be having rank 1 and hence won't be neglected.
One more way to this is by using union.
select * from my_table UNION select * from my_table

MySQL Ordering from another table

I have been looking for a solution for this for over an hour now and decided to resort to asking here.
I am creating a "Twitter-like", following system for users of my Website and I wanted to be able to display each and every one of the users that a specific user follows or is followed by, I also want to then order this by the timestamp on the follow table, descending so that the latest follower is at the top.
The solutions I have come across seem to use inner joins etc. which is all well and good, but I was wondering whether there is a logical solution for my current query to do this.
Table structures:
users:
id | username
follows:
id | follower_id | following_id | timestamp
My current query:
SELECT * FROM users WHERE id IN (SELECT follower_id FROM follows WHERE following_id = $user_id) ORDER BY id ASC
Of course this will simply order by the user ID, how would I (using the current query structure), be able to add the order to list by the follows timestamp?
MySQL INNER JOIN
"SELECT users.* FROM users
INNER JOIN follows ON follows.follower_id = users.id
WHERE follows.following_id = $user_id
ORDER BY follows.timestamp DESC";
You can sort using multiple columns like this:
ORDER BY [column1] [ASC|DESC], [columm2] [ASC|DESC], ...
Therefore, edit your query's order by clause to include the second column and sort it descending.
You must use a join to add the column; here's the basic syntax of a join:
SELECT [table_name].[column_name], ...
FROM [table1]
JOIN [table2] ON [join condition]
...
Your code should look somewhat like this:
SELECT users.*
FROM users
JOIN follows ON users.id = follows.following_id
WHERE follows.following_id = $user_id
ORDER BY users.id ASC, follows.timestamp DESC
As far as I know, there is no way to do this without joining the tables; perhaps its possible to sort the returned list, but no guarantees):
SELECT * FROM users
WHERE id IN (SELECT follower_id FROM follows
WHERE following_id = $user_id
ORDER BY timestamp DESC)
ORDER BY id ASC;
The above may or may not work (I didn't test it); if it does not, you must use a join query.

SQL: How to sort by sum of fields where certain conditions are met?

I have a shop that sells items
Every time an item is sold, following data is placed in a database:
-item_id
-item_count
-bought_value (money spent to buy this item, taking amount into consideration)
Now I would like to know the percentage of money that has come in PER ITEM
I would like to have this information sorted but I'm not fully sure how to do this
What I currently have is:
to find total money that has come in: SUM(boughtvalue)
to find all items: SELECT DISTINCT item_id
iterate through all items and use: SELECT SUM(boughtvalue) WHERE item_id = ...
This gets me the results, but they're not sorted this way
What I'm looking for is something like "SELECT DISTINCT item_id ORDER BY SUM(boughtvalue)"
My PHP script that finds this information currently displays something like this:
15332-0.75640207175834%
18353-0.30683127676158%
18349-0.53882565675204%
18351-0.20954331095913%
All I need is to have this information sorted.
You are looking for group by:
SELECT item_id, SUM(boughtvalue)
FROM table t
GROUP BY item_id
ORDER BY SUM(boughtvalue) DESC;
Try something like:
select item_id, sum(item_count), sum(bought_value) from item_table group by item_id
assuming your table name is item_table
Play around with something like this
SELECT item_id,
(
SUM( boughtvalue ) / ( SELECT SUM(boughtvalue) from tbl )
) as percentvalue
FROM tbl
GROUP BY item_id
ORDER BY percentvalue DESC;
Ususally I discourage subqueries, but I think the optimizer will optimize that away.
Try:
SELECT item_id, SUM(bought_value) as bought_value FROM item_table GROUP BY item_id ORDER BY bought_value

Get results from multiple rows with same names

I have some tables with various content. What I want to accomplish is to display the lets say 20 latest entries from those tables in a div.
Here is my first table - audio1
userID folder title date
the two other folders look exactly the same
audio2
userID folder title date
audio3
userID folder title date
How can I get the data from all the tables at the same time and echo them one by one to a div ordered by date with PHP?
SELECT userID, folder, title, date
FROM audio1
UNION ALL
SELECT userID, folder, title, date
FROM audio2
UNION ALL
SELECT userID, folder, title, date
FROM audio3
ORDER BY date DESC LIMIT 20;
Your SQL query will be a 3 part UNION. A UNION query concatenates results from multiple tables with (usually) similar structures, when a JOIN relationship is not needed but rather you just need to return rows from multiple tables.
$sql = "SELECT userID, folder, title, date FROM audio1
UNION ALL
SELECT userID, folder, title, date FROM audio2
UNION ALL
SELECT userID, folder, title, date FROM audio3
LIMIT 20;";
$result = mysql_query($sql);
if ($result) {
// Fetch results and echo them into a list.
}
You will need a column to ORDER BY. This is likely to be date, but you may have other plans. Add an ORDER BY clause before the LIMIT 20.
it seems that your database setup is wrong and you have to have only one table called 'audio' with a field represents the number you are currently using in the table name.
You may try the union, or you can try a join.
SELECT
COALESCE(t1.userID, t2.userID, t3.userID) as userID
, t1.folder, t1.title, t1.date
, t2.folder, t2.title, t2.date
, t3.folder, t3.title, t3.date
FROM table1 t1
FULL OUTER JOIN table2 t2 ON (t1.userID = t2.userID)
FULL OUTER JOIN table3 t3 ON (t1.userID = t3.userID)
It's a very different beast, so I'd thought I'd give you the option.

Categories