I have a form with radio buttons which stores the value (which is the ID) in my MySQL database along with the necessary information from the user.
INSERT INTO table (user_id, name, address, prefer_id) VALUES ('', ?, ?, ?);
So when I try to fetch the data, I use LEFT JOIN, to get the necessary description from table2:
SELECT a.name, a.address, b.prefer_desc FROM table a
LEFT JOIN table2 b ON a.prefer_id = b.prefer_id
WHERE a.user_id = ?
But I have created an other option, in case the option the user prefers is not in the list. A textbox will appear when the user selects Other in the list of radio buttons so they can type-in freely their preferred data. Check this fiddle to see an example.
The first logic that I've thinked of is to create a separate table which stores the typed-in data of the user.
other_tb:
other_id | user_id | typed_in |
----------+---------+----------+
1 | 1 | cake |
2 | 3 | pizza |
So when I fetch the data, I use php's if() condition if the prefer_id is 4 (or other), and if it does, I will use another SELECT query to get the other data in other_tb table.
SELECT typed_in FROM other_tb WHERE user_id = ?
Is there a way to do all of this in a single query?
OR
Is this the best option, or is there a right or better way in this kind of situation?
try this
SELECT
a.name,
a.address,
IF(a.prefer_id=4,(SELECT typed_in FROM other_tb WHERE user_id = a.user_id),b.prefer_desc) as prefer_desc
FROM table a
LEFT JOIN table2 b
ON a.prefer_id = b.prefer_id
WHERE a.user_id = ?
If you are using the second table as you described, and you want to keep the same format of the output and assuming the records in other_tb are unique for each user_id, you could use something like this:
SELECT a.name, a.address,
CASE
WHERE a.prefer_id = 4 THEN c.typed_in
ELSE b.prefer_desc
END CASE AS prefer_desc
FROM table a
LEFT JOIN table2 b ON a.prefer_id = b.prefer_id
LEFT JOIN other_tb c ON a.user_id = c.user_id
WHERE a.user_id = ?
I think this can also be written as:
SELECT a.name, a.address,
CASE a.prefer_id
WHERE 4 THEN c.typed_in
ELSE b.prefer_desc
END CASE AS prefer_desc
FROM table a
LEFT JOIN table2 b ON a.prefer_id = b.prefer_id
LEFT JOIN other_tb c ON a.user_id = c.user_id
WHERE a.user_id = ?
There are two approaches that I was able to practice depending on the situation:
Allow users to add more options so that their answer is still indexed to table2. So when fetching data, you may still use LEFT JOIN to get the user's preferred option without any other condition. But this method will allow users to see the options that was added by other users.
If the options are "fixed" and only the administrator is allowed to add options to table2, have another column to table1, which stores the other answer of the user (let say other_option column). This method allows the user to still freely state their option without adding options to table2.
Here is table1:
+---------+------+---------+-----------+--------------+
| user_id | name | address | prefer_id | other_option |
+---------+------+---------+-----------+--------------+
What I do is I put 0 to prefer_id if the user prefers to answer other_option. So your program expects that if the prefer_id is 0, you have an input in other_option.
Related
This question already has answers here:
How to resolve ambiguous column names when retrieving results?
(11 answers)
Closed 2 years ago.
I have some big tables which I need to combine into a single very large table, to form a single-page data export for a statistical package.
This is easy with INNER JOIN but the some of the tables have the same column names and these are being overwritten by each other when I fetch them as an array in PHP.
There are 4 tables being joined with 30-200 columns in each so there are far too many field names to manually include in the query with aliases, as would be the norm in this situation.
Here's the query:
SELECT * FROM logs
INNER JOIN logdetail ON logdetail.logID = logs.id
INNER JOIN clients ON clients.id = logs.clientID
INNER JOIN records ON records.id = logdetail.id
WHERE logs.userID=1
Is there any way around this? I don't actually mind what the column names are as long as I have the data so if I could prepend the table name to each field, that would do the trick.
I would create a view, your view would be comprised of your long query with aliases
Here is an example taken from the manual
mysql> CREATE TABLE t (qty INT, price INT);
mysql> INSERT INTO t VALUES(3, 50);
mysql> CREATE VIEW v AS SELECT qty, price, qty*price AS value FROM t;
mysql> SELECT * FROM v;
+------+-------+-------+
| qty | price | value |
+------+-------+-------+
| 3 | 50 | 150 |
+------+-------+-------+
This has always worked for me, unless you have one to many or some other relationship among these tables, which will duplicate records.
SELECT * FROM logs l
INNER JOIN logdetail ld ON ld.logID = l.id
INNER JOIN clients c ON c.id = l.clientID
INNER JOIN records r ON r.id = ld.id
WHERE l.userID=1
As andrew says you can also use a View to get this thing working which is much cooler.
I found a solution for this. Simply, fetch each duplicate column a second time, this time using an alias. This way, the overwritten values are selected again and aliased:
SELECT * FROM logs,
clients.name as clientName,
logs.name as logName,
etc...
INNER JOIN logdetail ON logdetail.logID = logs.id
INNER JOIN clients ON clients.id = logs.clientID
INNER JOIN records ON records.id = logdetail.id
WHERE logs.userID=1
Note: There is no need to do this for the final instance of the duplicate, because this column will not have been overwritten. So, in the example above, there is no need to include a line like records.name as recordName because, since there are no columns after it which have the same name, the record.name field was never overwritten and is already available in the name column.
tbl_teams: team_id | team_name
tbl_players: player_id | player_fname | player_sname | player_bplace | player_bdate
tbl_players_stats: player_id | season_id | player_squad_no | team_id | player_apps | player_goals
Sorry if this is a basic question, but from all the MySQL tables and columns above I'd like to join the tables and then display the results by which season_id and team_id is selected. I need using PHP like this:
player_squad_no | player_sname, player_fname | team_name | player_apps | player_goals
I've looked at examples on here but still can't figure out how to write the MySQL query to do it with three separate tables and how to specify the table name before the column name. I've seen some examples with only the initial. tt.teams for instance. Is Left Join the way to do it?
Any help would be much appreciated.
With three separate tables, you simply write the join like this:
SELECT *
FROM Table_A AS A
LEFT JOIN Table_B AS B USING(ID)
LEFT JOIN Table_C AS C USING(ID)
Note that USING(column) is a syntactic alternative to ON A.column = B.column that you can use when the columns you want to join on have the same name in both tables.
In the above example, the tables are aliased with AS so that you can refer to them by the alias instead of the full table name. (AS is actually optional; you can just give the alias immediately after the table, if you're paying by the character.) Try to choose an alias that makes sense when you look at it; often times people will alias like this:
SELECT a.Name, b.State
FROM Customers AS a
LEFT JOIN Orders AS b
...etc.
But if you have a longer query, how are you supposed to remember what tables a and b refer to? At the very least, it would make sense to alias Customers AS C and Orders AS O; in some cases, I would go a step further: Registration AS REG, for instance. This gets more and more important as you JOIN more and more tables together.
Here's one way to write your query:
SELECT
Stats.player_squad_no,
CONCAT_WS(', ', Players.player_sname, Players.player_fname) AS player_full_name,
Teams.team_name,
Stats.player_apps,
Stats.player_goals
FROM tbl_players AS Players
LEFT JOIN tbl_players_stats AS Stats USING(player_id)
LEFT JOIN tbl_teams AS Teams USING(team_id)
The CONCAT_WS() function is included to assemble the player's full name the way you indicated you wanted it to be displayed. Since this function will output a column with a messy name, I also gave it an alias.
This should work
SELECT tbl_players_stats.player_squad_no,
tbl_players.player_sname,
tbl_players.player_fname,
tbl_teams.team_name,
tbl_players_stats.player_apps,
tbl_players_stats.player_goals
FROM tbl_players
JOIN tbl_players_stats ON tbl_players.player_id = tbl_players_stats.player_id
JOIN tbl_teams ON tbl_teams.team_id = tbl_players_stats.team_id
SELECT player_squad_no , player_sname, player_fname,team_name, player_apps, player_goals
FROM tbl_players_stats as s
JOIN tbl_players as p ON s.player_id=p.player_id
JOIN tbl_teams as t ON s.team_id=t.team_id
Nothing Joining is simple concept. But we should use proper columns for tables. While selecting the list of columns to select we should be little careful by using table aliasing. Try the below code
select c.player_squad_no,b.player_sname,b.player_fname,a.team_name,c.player_apps,c.player_goals
from tbl_teams a,tbl_players b,tbl_players_stats c
where a.team_id=c.team_id
and b.player_id=c.player_id
I have two mysql tables members_tbl and post_tbl
members_tbl:
id|userName |fname |lname |friendArray
post_tbl:
postId| memId | thePost |postDate
now, I'm trying to display post from user id and from his friendArray.
please let me know how to do it (still new to php)
Since MySQL lacks an explode function, you either need to create a relation table and use joins, or use multiple queries with php processing inbetween. I strongly recommend the relational approach as it conforms to database standards (normalization) much more than the alternative and is easier to implement.
You need a third table, which describes the relation between two friends, I.E.
friends_tbl
user1_id | user2_id
With a primary key on user1_id and user2_id (thereby preventing duplicates). For every friend relationship, I.E. user 1 is friends with user 2, there is one row in this table. You can then get the listing you want with the following query.
SELECT p.*, u.*
FROM posts_tbl p
INNER JOIN members_tbl u
ON u.id = p.memId
WHERE u.id IN (
SELECT user2_id AS id
FROM friends_tbl
INNER JOIN members_tbl
ON (user1_id = id)
WHERE members_tbl.id = $id
UNION
SELECT user1_id AS id
FROM friends_tbl
INNER JOIN members_tbl
ON (user2_id = id)
WHERE members_tbl.id = $id
)
ORDER BY p.postDate
SQLFiddle of the above.
create a different table for your friend-relations and then join this table in your SQL.
i have an Table with Users and an Table with events that is related to the id from the Users Table. In each Event you can make points and i want to get the total points from an specific User.
It looks like this:
Users
+----+----------+
| id | username |
+----+----------+
Events
+----------+---------+--------+
| event_id | user_id | points |
+----------+---------+--------+
// The event_id is related to an Event Table with specific data about the Event. but that not relevant.
The best could be to get the data from the user and the total points that he got in one query.
Thanks and Greetings,
Mottenmann
"..to get the data from the user and the total points that he got in one query."
You need to join both tables first so you can manipulate the data. The query below uses INNER JOIN which only includes users on the result list if it has atleast one matching record on the Events. If you want to get all users even without a single matching record on the other table, use LEFT JOIN instead.
SELECT a.ID, a.username, SUM(b.points) totalPoints
FROM Users a
INNER JOIN Events b
ON a.ID = b.user_ID
GROUP BY a.ID, a.username
To further gain more knowledge about joins, kindly visit the link below:
Visual Representation of SQL Joins
"In each Event you can make points and i want to get the total points
from a specific User."
You could do something like this:
select sum(e.points) as points from users u
left join events e ON (u.id = e.user_id)
WHERE u.id = {$id}
where {$id} is the id of user.
I Have two Tables tblSiteVisits and tblConformedList and Colums as Below
tblSiteVisits
Name | EmailAddress
tblConformedList
Name | EmailAddress | ContactNo | Location | Conform_Status
The First Table Contains Name and EmailAddress of all those who have SiteVisits
Now in the Second table Conform_Status will be set either to 1 or 0 based on the client availability at point of time for site visit.
If not I will fill the ContactNo and Location and just update the table with Conform_Status = 0.
Now what i want is I want to take the Name and EmailAddress of people from table tblSiteVisits and tblConformedList by relating the EmailAddress in join and the rows in tblConformedList whose Conform_Status is 0.
That is List of people who have given ContactNo and Location for update but not given the Conform_Status.
Thanks in Advance
May be it helps you.
select t1.* from tblSiteVisits t1 inner join tblConformedList t2 on
t1.EmailAddress=t2.EmailAddress where t2.Conform_Status=0
Try it and share your feedback.
Sorry, if you only need the rows where Conform_Status is 0, you don't need a LEFT JOIN, you need an INNER JOIN.
SELECT v.*
FROM tblSiteVisits v
JOIN tblConformedList c
ON v.EmailAddress = c.EmailAddress
WHERE c.Conform_Status=0
Because the c.Conform_Status=0 will filter out all rows where it is not 0, including the rows with NULL, rows in tblSiteVisits that have no correspondent row in tblConformedList will be filtered anyway - hence just use an INNER JOIN.
If you want an entry for all rows, then you can left-join, put the where-clause in the on-clause or add a OR Conform_Status IS NULL in your where clause.
SELECT v.*
FROM tblSiteVisits v
LEFT JOIN tblConformedList c
ON v.EmailAddress = c.EmailAddress
AND c.Conform_Status=0
This will display each row in tblSiteVisits, and if possible, the data for tblConformedList, but only when Conform_Status is actually 0.