where id = multiple artists - php

Any time there is an update within my music community (song comment, artist update, new song added, yadda yadda yadda), a new row is inserted in my "updates" table. The row houses the artist id involved along with other information (what type of change, time and date, etc).
My users have a "favorite artists" section where they can do just that -- mark artists as their favorites. As such, I'd like to create a new feature that shows the user the changes made to their various favorite artists.
How should I be doing this efficiently?
SELECT *
FROM table_updates
WHERE artist_id = 1
OR artist_id = 500
OR artist_id = 60032
Keep in mind, a user could have 43,000 of our artists marked as a favorite.
Thoughts?

This depends on how your database is setup. If I had my way, I'd set it up with a table like so:
Table: user_favourite_artist
user_id | artist_id
---------------------
1 | 2
1 | 8
1 | 13
2 | 2
3 | 6
6 | 20
6 | 1
6 | 3
user_id and artist_id together would be a composite primary key. Each row specifies a user, by id, and an artist they have as a favourite, by id. A query like so:
SELECT artist_id FROM user_favourite_artist WHERE user_id = 1
Would give you the artist_id's 2, 8, and 13. This is a very simple query that will scale to your expectations.
On the reverse, when an artist is updated, you'd run this query:
SELECT user_id FROM user_favourite_artist WHERE artist_id = 2
And you would get the user_id's 1 and 2. This will tell you which users to notify. This query is also simple and will scale.

Maybe you can try this:
SELECT *
FROM table_updates
WHERE artist_id IN(1, 500, 60032)

If you have the marked artists in a secondary table, I would recomend rather using a join.
Something like
SELECT *
FORM table_updates tu INNER JOIN
table_marked_by_user tmbu ON tu.artist_id = tmbu.artist_id
WHERE tmbu.user_id = $user_id

If you're on SQL Server, you can use a nested select statement:
select * from table_updates where artist_id in
(select artist_id from favorites_table where user_id = 10)
If you don't mind doing dirty reads, you can speed it up with (nolock).
select * from table_updates (nolock) where artist_id in
(select artist_id from favorites_table (nolock) where user_id = 10)

Related

subquery returns more than one row for this query [duplicate]

I want to select information from two SQL tables within one query, the information is unrelated though, so no potential joints exist.
An example could be the following setup.
tblMadrid
id | name | games | goals
1 | ronaldo | 100 | 100
2 | benzema | 50 | 25
3 | bale | 75 | 50
4 | kroos | 80 | 10
tblBarcelona
id | name | games | goals
1 | neymar | 60 | 25
2 | messi | 150 | 200
3 | suarez | 80 | 80
4 | iniesta | 40 | 5
I want to have a query that gives me the following:
name | games | goals
messi | 150 | 200
ronaldo | 100 | 100
I tried to follow this logic: Multiple select statements in Single query but the following code did not work:
USE Liga_BBVA
SELECT (SELECT name,
games,
goals
FROM tblMadrid
WHERE name = 'ronaldo') AS table_a,
(SELECT name,
games,
goals
FROM tblBarcelona
WHERE name = 'messi') AS table_b
ORDER BY goals
Any advice on this one? Thanks
Info: The football stuff is just a simplifying example. In reality it is not possible to put both tables into one and have a new "team" column. The two tables have completely different structures, but I need something that matches the characteristics of this example.
You can do something like this:
(SELECT
name, games, goals
FROM tblMadrid WHERE name = 'ronaldo')
UNION
(SELECT
name, games, goals
FROM tblBarcelona WHERE name = 'messi')
ORDER BY goals;
See, for example: https://dev.mysql.com/doc/refman/5.0/en/union.html
If you like to keep records separate and not do the union.
Try query below
SELECT (SELECT name,
games,
goals
FROM tblMadrid
WHERE name = 'ronaldo') AS table_a,
(SELECT name,
games,
goals
FROM tblBarcelona
WHERE name = 'messi') AS table_b
FROM DUAL
The UNION statement is your friend:
SELECT a.playername, a.games, a.goals
FROM tblMadrid as a
WHERE a.playername = "ronaldo"
UNION
SELECT b.playername, b.games, b.goals
FROM tblBarcelona as b
WHERE b.playername = "messi"
ORDER BY goals;
You can union the queries as long as the columns match.
SELECT name,
games,
goals
FROM tblMadrid
WHERE id = 1
UNION ALL
SELECT name,
games,
goals
FROM tblBarcelona
WHERE id = 2
You can combine data from the two tables, order by goals highest first and then choose the top two like this:
MySQL
select *
from (
select * from tblMadrid
union all
select * from tblBarcelona
) alldata
order by goals desc
limit 0,2;
SQL Server
select top 2 *
from (
select * from tblMadrid
union all
select * from tblBarcelona
) alldata
order by goals desc;
If you only want Messi and Ronaldo
select * from tblBarcelona where name = 'messi'
union all
select * from tblMadrid where name = 'ronaldo'
To ensure that messi is at the top of the result, you can do something like this:
select * from (
select * from tblBarcelona where name = 'messi'
union all
select * from tblMadrid where name = 'ronaldo'
) stars
order by name;
select name, games, goals
from tblMadrid where name = 'ronaldo'
union
select name, games, goals
from tblBarcelona where name = 'messi'
ORDER BY goals
Using union will help in this case.
You can also use join on a condition that always returns true and is not related to data in these tables.See below
select tmd .name,tbc.goals from tblMadrid tmd join tblBarcelona tbc on 1=1;
join will help you even in case when tables do not have common columns
You can use UNION in this case
select id, name, games, goals from tblMadrid
union
select id, name, games, goals from tblBarcelona
you jsut have to maintain order of selected columns ie id, name, games, goals in both SQLs
as i see you want most goals in each team
you can try this
select name,games,max(goals) as 'most goals' from tblRealMadrid
union
select name,games,max(goals) as 'most goals' from tblBarcelona
In your case, the two tables have completely different structures and cannot be joined.
The UNION operator could be used. The UNION operator joins the results of two or more SELECT statements to produce a single result set. The first column in the SELECT statement is used to sort the result set.
SELECT name, games, goals
FROM tblMadrid
WHERE name = 'ronaldo'
UNION
SELECT name, games, goals
FROM tblBarcelona
WHERE name = 'messi'
ORDER BY goals;
Each SELECT statement must have the same number of columns and data types that are compatible. Also, if you want to keep the duplicates, use UNION ALL rather than UNION.

Sum 3 Tables and Subtract the User Request

Hello Developers/Programmers
I am working on withdrawal function on my website.
So it goes like this
I need to total the 3 tables i have by User ID with status of '1' ,and Subtract the Inputed amount by the User Requested the Withdrawal
These are my 3 tables
tbl_bonus_1
id | amount | user_id | status
1 20 1 1
2 20 1 1
3 20 3 1
tbl_bonus_2
id | amount | user_id | status
1 30 1 1
2 30 1 1
3 30 3 1
tbl_bonus_3
id | amount | user_id | status
1 40 1 1
2 40 1 1
3 40 3 1
Now I need to get all that 3 tables by USER ID and get the total of it.
After getting the total i need to subtract the Inputted quantity of the USER
and update the status to 0 so that the user cant withdraw again.
Im using Codeigniter 3.1.5
select user_id, sum(amount)
from
(select * from tbl_bonus_1
union
select * from tbl_bonus_2
union
select * from tbl_bonus_3) tt
where status = 1
group by user_id
DEMO:
http://sqlfiddle.com/#!9/7f1807e/1
And UPDATE (single user):
UPDATE tbl_bonus_1 t1 INNER JOIN tbl_bonus_2 t2
ON t1.user_id = t2.user_id
INNER JOIN tbl_bonus_3 t3
ON t1.user_id = t3.user_id
SET t1.amount = 0, t2.amount = 0, t3.amount = 0
WHERE t1.user_id = 1;
Realistically, you don't want to subtract from these tables if you want to manage a balance. You need to add a 4th table that is withdrawal amount, so you can capture the transactions. If you have a total of 160 across 3 tables, and the user withdrawals 150, how would you determine which to decrement.
I would suggest actually consolidating all of these into 1 trasaction table, and capture the amounts there.
So to get what you need you will need to leverage variables which will need to be passed to the query. Below will give you what you are asking for. That being said, this is not the correct way to do this. Also, there is no way to determine which of the 3 balances you want to subtract the withdraw from. This is just not how transaction ledgers work and for a lot of reasons I am not going to get in to right now. At the bottom of this answer is how I suggest you should build your table. You will be able to get information with more easy while capturing more/better data.
How to get data from current structure:
set #withdraw = 150.00, #user = 1;
select user_id, sum(amount) as prevBalance
, #remainingBalance := if(#user = user_id,sum(amount)-#withdraw,sum(amount)) as remainingBalance
from
(select * from tbl_bonus_1
union
select * from tbl_bonus_2
union
select * from tbl_bonus_3) balance
group by user_id;
How you should build your schema:
CREATE TABLE ledger (id int NOT NULL AUTO_INCREMENT
,user_id int
, amount decimal(5,2)
, transaction_type varchar(20)
,PRIMARY KEY (ID));
INSERT INTO ledger VALUES
(null,1,20,'Bonus1'),
(null,1,20,'Bonus1'),
(null,3,20,'Bonus1'),
(null,1,30,'Bonus2'),
(null,1,30,'Bonus2'),
(null,3,30,'Bonus2'),
(null,1,40,'Bonus3'),
(null,1,40,'Bonus3'),
(null,3,40,'Bonus3'),
(null,1,-150,'Withdraw')
;
Then all you would need to do is run the following query.
select user_id, sum(amount) balance from ledger
group by user_id;

Convert multiple select query to Doctrine DQL

Tables:
items with field id
id
--
1
2
3
item_photos with fields id, item_id, photo,status. Status is 0 or 1.
id | item_id | photo | status
-----------------------------
1 1 a.jpg 1
2 1 b.jpg 1
3 1 c.jpg 2
4 2 d.jpg 1
item_photos item_id is a foreign key on items.id
Entities:
Item entity has OneToMany on ItemPhoto
class Item {
/**
* #ORM\OneToMany(targetEntity="ItemPhoto", mappedBy="item")
*/
private $itemPhotos;
Problem:
I want to return all records from items, together with either one photo with status=2 or any other first photo for the same item_id in the item_photos table, or null if no photos found, in a single query.
Note: not all items have photos in item_photos with status=2.
In a Repository class I have this so far, it works but not what I want:
//Solution can be using query builder, or create query, doesn't matter
//
$em = $this->getEntityManager();
$dql = "SELECT i,
(SELECT p.photo FROM AppBundle:ItemPhoto p WHERE p.status='2' AND p.item=i.id) as photo1,
FROM AppBundle:Item i";
$query = $em->createQuery($dql);
When I add another select into this query (SELECT p.photo FROM AppBundle:ItemPhoto p WHERE p.item=i.id LIMIT 0,1) as photo2, it gives me error. I could write it with SQL using IFNULL() but then DQL doesn't support IFNULL out of the box.

" People Who Liked this Also Liked " Query in Mysql PHP

Music table
id | title
1 Rap God
2 Blank Space
3 Bad Blood
4 Speedom
5 Hit 'em up
Like table
u_id | m_id
1 1
1 2
1 4
1 5
2 3
2 4
2 5
3 1
3 5
4 1
4 2
4 5
Now if someone visits music with m_id = 1
Then the output might be like
m_id
5
2
4
To explain this a bit...
As m_id = 1 is liked by users -> {1,3,4} which in turn likes ->{2,4,5} musics. Since m_id=5 is liked by max number of users its first followed by m_id = 2 and m_id = 4.
My Try
I queried the users who liked m_id = 1
SELECT u_id FROM likes WHERE m_id =1
Then i stored in in an array and selected each of their likes and
arranged them in desc order of count.
But it is a very slow and long process is there any way i can do this ?
p.s I have heard of Association Rules and Bayesian theorem can be user to achieve this. But can anyone help me out with an example ?
You can JOIN back on the Like table and do something like this.
SELECT also_like.m_id, COUNT(also_like.m_id)
FROM [like] AS did_like
JOIN [like] AS also_like ON
also_like.u_id = did_like.u_id
AND also_like.m_id != did_like.m_id
WHERE did_like.m_id = 1
GROUP BY also_like.m_id
ORDER BY COUNT(also_like.m_id)
Essentially you are getting a list of users who liked an item then getting a complete list of those user's likes excluding the item they just liked.
You can then add a HAVING clause or LIMIT to filter things down a bit more.
using a subquery ...
SELECT m_id, count(u_id) as Rank FROM `like`
WHERE u_id in
(
SELECT u_id
FROM `like`
WHERE m_id = 1
)
AND m_id <> 1
GROUP BY m_id
ORDER BY Rank DESC
and optionally
LIMIT 0, 10
or how many "alsolikes" you want to display

Select from three tables

I have three tables where table_2 is the middle(connected) between table_1 and table_3
tables
table_id
...
...
table_rest
rest_id
table_id
...
rest
rest_id
...
...
And the query to select I use
SELECT m.table_id, table_name
FROM tables m
JOIN table_rest mr
ON m.table_id = mr.table_id
WHERE rest_id = '$rest_id'
What I need now is to join in this query another table reserv
id
...
status
To check if status is 0, 1,or 2 to not show me anything if there is no status this mean there is no record to show me. In other words this is resserved system where I show on screen few tables. If status is 0,1,2 thats mean the table is taken. If nothing is found for status this mean that there is no record for table and can be shown to user.
EDIT: Sample scenario
tables
table_id
1
2
3
4
5
rest
rest_id
1
2
table_rest
table_id | rest_id
1 2
2 2
3 2
4 2
5 2
So the query that is above will generate 5 tables for rest_id=2 and none for rest_id=1
So now I have another table
reserv
id | status
1 0
2 1
3 2
So in this table reserv currently are saved 3 tables. The idea is to show me other two whit id=4 and id=5 because they are not in table reserv and don't have any status.
Hope is a little bit more clear now.
You have to point from table reserv to which table is beign booked, let's call it reserv.table_id
SELECT m.table_id, table_name
FROM tables m
JOIN table_rest mr
ON m.table_id = mr.table_id
left join reserv
on reserv.table_id = m.id
WHERE rest_id = '$rest_id'
and reserv.status is null (*note)
*note use 'is' or 'is not' depending of your needs, as far as I read, first seems that you want !=, later that what you want is =
It's better if you provide sample data or sqlfiddle. Based on what I realize: Is this what you want:
select tables.table_id, rest.rest_id
from tables
left join table_rest on table_rest.table_id = tables.table_id
left join rest on rest.rest_id = table_rest.rest_id
where rest.rest_id = '$rest_id'
and tables.table_id not in (select id from reserv)

Categories