MySQL 2 tables with common column only match if other condition exist - php

Not sure how to explain this exactly but here goes.
I have these tables:
messages:
------------------------
|msgid|clientid|message|
------------------------
|1 |536 |Hello |
------------------------
|2 |543 |Hello |
------------------------
|3 |529 |Hello |
------------------------
clients:
----------------------
|cleintid|wholesaleid|
----------------------
|536 |479 |
----------------------
|543 |480 |
----------------------
|529 |479 |
----------------------
I want to only pull records from the messages table if the client id in the message record is owned by clients.wholesaleid = 479.
So that should pull records 1 and 3 from the messages table.
I know how to do with with completely separate multiple nested queries but I know there is a smarter way to do this with pure SQL in one query. I have been putting on learning this for way too long so I am here to figure this out.
Normally what I would do in this instances is do a simple query and loop through the clients table looking for all client id's that match the wholesale ID. I would stuff them all in an array or, as I loop through them, do a separate query for all messages for that one client id. It's gross and I know there is a better way. Tons of loops, within loops and slow as heck if my data set gets large.
I know this isn't correct but I am hoping it will help illustrate what I am trying to do.
Something like this but without multiple loops:
SELECT * FROM clients WHERE wholesaleid = 479;
For Each Loop Here
SELECT * FROM messages WHERE clientid=ThisClientID
For Each Loop #2 HERE
Print msgid, clientid, message
End For Each Loop #2
End For Each Loop
Sorry this is so confusing, just not sure how to better explain how I do it now and where I am trying to get.
I am guessing everyone will tell me to go learn JOINS but, I have spent plenty of time on that and I am not sure how it applies if at all for what I am trying to accomplish.

Use INNER JOIN(cleintid in table clients might be a typo in your question):
SELECT messages.*
FROM messages
INNER JOIN clients
ON messages.clientid = clients.cleintid
AND wholesaleid = 479;
SQLFiddle Demo

YOU CAN JOIN THOSE TWO TABLE
SELECT m.*
FROM messages m
INNER JOIN clients c
ON m.clientid = c.clientid
AND c.wholesaleid = 479;

Related

Linking 2 IDs to display either one depending on which is being addressed

I have a games database and I need to create pairs of similar games in another table. So, let's say, game ID 5 and ID 12 need to be paired, which should be like this:
---------------------------
| PairID | First | Second |
---------------------------
| 1 | 5 | 12 |
---------------------------
So what I need basically is to join pairs and games tables and select and display data for all IDs of each pair depending on which game is being browsed. That is, if it's game ID 5 then ID 12 should be displayed and vice versa. Seems pretty trivial at first, except I discovered there is no neareast elegant solution to this, where the major problem is the order of IDs in the pairs table.
First of all, with this scheme I'm forced to use two separate joins of the 'games' table and select both games' data regardless like this:
SELECT simpairs.id, simpairs.first, simpairs.second,
games_one.id AS first_id, games_two.id AS sec_id,
games_one.title AS first_title, games_two.title AS sec_title,
games_one.year AS first_year, games_two.year AS sec_year
FROM simpairs
LEFT JOIN games AS games_one ON simpairs.first = games_one.id
LEFT JOIN games AS games_two ON simpairs.second = games_two.id
WHERE simpairs.first = <id> OR simpairs.second = <id>
Secondly, I need the script to pick out and display the correct data like this:
$id = $_GET['id'];
while($row = mysqli_fetch_assoc($res)) {
if($row['first_id'] != $id) {
$game_id = $row['first_id'];
$title = $row['first_title'];
$year = $row['first_year'];
} else {
$game_id = $row['sec_id'];
$title = $row['sec_title'];
$year = $row['sec_year'];
}
...
}
Ok, so this is already pretty messy. Still, the biggest issue is sorting the output alphabetically. Obviously, it can't be easily done on the SQL side unless the query is somehow rebuilt for which there is no apparent route as it must include an equivalent for PHP condition, or the pairs table should be modified to contain a mirrored pair for each new entry like this:
---------------------------
| PairID | First | Second |
---------------------------
| 1 | 5 | 12 |
---------------------------
| 2 | 12 | 5 |
---------------------------
This would work of course and I would only need 1 join instead of 2, which would also make sorting easier directly on the SQL side, yet this also doesn't seem very elegant as I would have to perform two inserts for each new pair instead of just 1 plus clutter the database with mirrored entries making it exactly 2 times larger. I mean, if this is the right way then I guess I'm fine with that.
Sorting data on the script side is no less daunting. Typically, arrays are used for the occasion, except this time around I don't see how it can be achieved effectively. I will need to store ID, game title and year of release somehow and then sort everything based on titles alone. Meaning, I should be probably using 2 dimensional arrays where titles act as parent keys for sub-arrays containing IDs and years, then I should somehow sort only the parent keys without affecting the sub-arrays and I really don't know how to do that nor if it's worth it at all. All in all, seems like unnecessary strain to both the database and the script.
So what would be the optimal solution here?
You have an id that relates to a game in the games table.
You have a table that links other game id's to the main game id
You want to show a list of those linked games and related info.
Select lg.*
FROM `games` g
LEFT JOIN `simpairs` s
ON s.first = g.id OR s.second = g.id
JOIN `games` lg // linked games
on lg.id = case when s.first = g.id then s.second else s.first end
where g.id = ?
Let me know if you have any questions, it's pretty self explanatory. Though it does assume simpairs never has reverse duplicate values in first and second otherwise you might need to filter those out.

INSERT INTO after CONCAT data from different columns from different rows

So, I have this MySQL table. Here are the relevant columns:
| raw line | composed_line | next_line
|----------------------|---------------|------------------------
| | | When I have a bad day,
| I cry my eyes out. | | When I cry my eyes out,
| I get ice cream. | | When I get ice cream,
| Things seem better. | | When things seem better,
| I get out of bed. | | When I get out bed,
I have this query, which does what I want it to do - it selects the data from the 'next line' column of the penultimate row and combines it with the data from the 'raw_line' column of the most recent row.
SELECT CONCAT((SELECT `next_line` FROM `lines` ORDER BY id DESC LIMIT 1 OFFSET 1),
(SELECT `raw_line` FROM `lines` ORDER BY id DESC LIMIT 1))
So the result looks like
When things seem better, I get out of bed.
However, all my attempts to take this result and insert it into a column called 'composed_line' of the most recent row have failed. I have tried using PHP and SQL to do this, none of which work.
I wouldn't need to do this if I could figure out a way to display (in PHP) the whoooole table with the 'next_line' and 'raw_line' concat'd and sorted by ID asc, but my attempts to do that have also been dismal failures, always displaying the 'next_line's together, then the 'raw_lines' together, or some other unwanted crappy result (doublesadface).
The result I would want would look like:
When I have a bad day, I cry my eyes out.
When I cry my eyes out, I get ice cream.
When I get ice cream, things seem better.
When things seem better, I get out of bed.
I am brand new to SQL. Any help would be much appreciated.
Assuming you have an "id" column, you'd be better off using it with a join:
update line a
join line b on a.id = b.id-1
set a.composed_line = concat(a.next_line,' ',b.raw_line)
where b.raw_line is not null;
or, to just display it:
select
concat(a.next_line,' ',b.raw_line)
from
line a
join line b on a.id = b.id-1
SQLFiddle here
SELECT CONCAT(nextlines.next_line, rawlines.raw_line) AS line
FROM `lines` rawlines
JOIN `lines` nextlines
ON rawlines.id = (nextlines.id % (SELECT COUNT(*) FROM `lines`)) + 1
ORDER BY rawlines.id ASC
See SQL Fiddle demo.
The only slightly complex bit is the modulus (%) with the number of records so that the last ID in rawlines will join to the first ID from nextlines.

Creating tables on registration in php

The question is not new in any way but it has a small twist to it.
My webpage is a membership page where users places bets. My idea is to create a new table for the users(with a naming convention like TABLE userBet+$userid) bets. User login information is already handled, my goal is now to save the bets of the user to a new table. A table which is created when users register. This will hopefully make score counting easier. Am I right or wrong? Could this be done in a better way? (Everything is done in PHP MySQL)
User registers -> Table for bets get created
"CREATE Table $userID ,id_bet, games, result, points"
And then matching this table against the correct result?
So again my questions: Is this a good way to do it? Is creating a table with the userID a smart thing to do?
EDIT
The bets is always 40 matches, which makes the tables Huge with columns and rows.
Should I make 40 Tables, one for each games instead? and put all users in there?
Am I right or wrong?
You are wrong. Dynamically altering your database schema will only make it harder to work with. There's no advantage you gain from doing so. You can do the same things by storing all bets within the same table, adding a column userid.
Posting as an answer due to author's request : )
Suggested database schema:
table matches:
id | name |
---------------
1 | A vs B |
table user_bets
id | user_id | match_id | points | result |
-------------------------------------------
1 | X | 1 | Y | Z |
Where match_id is related on matches.id
user_id = user.id
user_bets is only one table, containing all the info. No need of separate tables, as it was clear from the comments it's considered bad practice to alter the db schema via user input.

Multiple users table VS 1 users table?

I am in dilemma situation. I am not sure if its a good idea to separate the users table. I notice my game highscores table performances, as the numbers growing, the loading is getting slower and slower.
My current users table store all users, which currently about 10k users. I am thinking of splitting the users table (for future) into like this:
Login Table => store user login details
==========================================
= id | username | password | tableid =
==========================================
= 1 | user1 | user1xx | 1 =
= 2 | user2 | user2xx | 1 =
...
= 20k1 | user20k1 | user20k1 | 2 =
etc
Users Data
==========================================
= id | money | items | preferences =
==========================================
= 1 | xx | xx | xx =
= 2 | xx | xx | xx =
...
= 20k1 | xx | xx | xx =
etc
So, when I try to get users data I just LEFT JOIN query to get the data.
My question is, are there any differences (speed, performances etc) between storing users data in multiple tables and storing users data in single table? (assume indexes and primary key are the same)
My current tables indexes:
Games highscores table => columns: id, gameid, name, score, date
Primary key : id
Indexes: gameid
Login Table => Columns: id, username, password
Primary key: id (userid)
Indexes: username
Users data => Columns: alots
Indexes: id
It sounds that the real question you have here is this: why ma app is slow. First of all splitting data between several tables is not going to help performance. If done right (for reasons other than performance) it will not hurt performance but I doubt it will help.
What's more, in my experience it is a bad idea to optimize based on gut feel. Somehow guesses about what holds your program back are usually wrong. You end up doing a lot of rewriting without any gain in speed.
The first step to speed it up is to find the real bottleneck. You need to add instrumentation and collect some stats to figure out - is it database or app server. Is it a particular sproc or might be the bandwidth of your network. Or may be it is some javascript on your pages.
Only after you know what to fix you can try to fix it.
Sounds like splitting the table won't do you any good. It seems like a 1:1 correlation would occur between the tables, and that would simply add a second query whenever you wanted something from that table.
Try using Partitioning on the table to help with performance in that aspect.
Normalizing is only useful if you have redundant data (so, you have the same user in your user table 5 times). Helpful if you want to lower data usage with particular users' high scores for multiple games, but ultimately it probably won't give you a performance increase on the table.
If you're querying for bits of information and you have lots of (edit:)columns, it's actually a really good idea to have them separated and you don't need the tableid field in the users table, all you need is a foreign key in the information table that points to the associated user in the users table.
You can have multiple tables like that and join them as you like, performance will most likely increase.

PHP MySQL Getting Data Out of Multiple Tables

I asked a similar question yesterday which may have been poorly worded, either way I didn't understand and this is something I really need to crack :) I've never done it before and would be very useful for so many of my projects.
This is for a directory website. I have three tables: entry, location, and entry-locations. entry contains information about a building such as name, address, image, etc. location is simply a list of possible locations each building could be. The location table is pretty much irrelevant for this example, it just contains information about the location which I could display on other areas of the site.
entry-locations is a table which links the entries to the locations. It only has two fields, entry-id and location... If you're wondering why I need a seperate table for this is because the same building could have multiple locations (don't ask).
Basically, what I need to do is display listings from each location it's own page. For example, I need to list every building in France, so the query needs to go through the entry-locations table returning every record with the location 'France', then it needs to pull all the data from the entry table corresponding to the entry-id's returned.
I'm sure there is a way to do this with one query and would be extremely greatful if I could be shown how, I could replicate this in so many projects.
How about this one?
-- // Selects all the columns from both entry-locations and entry
SELECT *
FROM entry-locations
JOIN entry e ON e.id = el.entry-id
WHERE el.location = 'France';
-- // To just get the entry data for matching records: (Remove DISTINCT if you
-- // don't mind, or want, each entry with multiple locations in the result set
-- // multiple times)
SELECT DISTINCT e.*
FROM entry-locations el
JOIN entry e ON e.id = el.entry-id
WHERE el.location = 'France'
Edit: Ok, so I tried removing the location table, and instead used entry-location.location as the name of the location.. Is this correct?
Imagine you have this data:
Entry:
|id|name|
| 1|Foo |
| 2|Bar |
Entry-Location:
|entry-id|location|
|1 |France |
|2 |Greece |
|2 |France |
This is how I understand the tables from your description. A more common approach is to have
Entry(id,name)
Location(id,name)
Entry_Location(entry_id, location_id)
This is also the source of some of the confusions in the other posts, I think.
Now, ask MySql to fetch data from both tables, where the id's match up.
SELECT entry.*
FROM `entry`, `entry-location` as el
WHERE entry.id = el.`entry-id`
AND el.location = 'France';
MySql now treats your data like one table, looking like this:
|entry.id|entry.name|el.location|
| 1| Foo| France|
| 1| Foo| Greece|
| 2| Bar| France|
And from that table it selects the entries where el.location = 'France', and returns the specified fields.
This query fetches all the fields from the entry table that matches the requirements you set.
First it makes MySql think of the two tables as one table, by SELECT-ing from both of them.
Have a look at MySql's SELECT reference.
select * from entry where id in (select entry-id from entry-locations)
If I got your idea, you need:
select e.* frmm entry join entry-locations as as l ON l.entry-id=e.id WHERE l.location='France'

Categories