I don't know which way would be better for PHP and SQL.
I design and program my own comment system and I would like id2=0 its a comment and id2>0 its sub-comment in one table. This means that if someone wrote a sub-comment in a comment with ID=1, then ID2 is responsible for assigning (sub-comment) to ID=1 (comment).
I have one table comments like this:
id | id2 | smt | etc.
1 | 0 | x | x //comment with sub-comment where id=3
2 | 0 | x | x //comment
3 | 1 | x | x //that is sub-comment for comment where id=1
I'm displaying this in a while loop because I need to print all the data from comments. Like this:
$sqlkom="SELECT * FROM `comments` WHERE `id`='".$row['id']."' ORDER BY id DESC LIMIT 20";
if($resultkom = mysqli_query($con, $sqlkom)){
if(mysqli_num_rows($resultkom)){
while($rowkom = mysqli_fetch_assoc($resultkom)) {
echo HtmlFormatFunction($rowkom['id'],$rowkom['id2'],$rowkom['smt'],$rowkom['etc'])
I won't achieve this: if($rowkom['id']==$rowkom['id2']) without adding another while() loop, right?
or maybe it is enough to modify the SQL query to achieve this effect? Please, help me with the right solution.
You can join your table with itself, something like that:
SELECT c.id, c.id2, c.smt, c.etc,
s.id, AS s_id, s.id2 AS s_id2, s.smt AS s_smt, s.etc AS s_etc
FROM `comments` c LEFT JOIN `comments` s
ON c.id = s.id2
WHERE c.id = ?
ORDER BY c.id DESC LIMIT 20";
Then you should get minimum one line for the first comment or as much as lines for the first comment as there are sub-comments. Then the first four fields will repeat, but thats not an issue. Maybe this is not perfect. Hope you get the idea.
Related
I wonder if someone could help me with an SQL query.
I am trying to display all results except where in Table 2 both the userid column equals 1 and the hidden column equals 1.
I am basically trying to hide results from individual users based on their id and the value in the hidden column either 1 or empty.
I have so far managed to make a query that does the opposite and can't figure out how to change it. I have tried adding !=, <>, NOT and a few other things, but nothing is working for me!
Here is the query I am working with.
$stmt = $conn->prepare("SELECT tl.id, tl.name, tl.locale, uh.hidden
FROM theList AS tl
LEFT JOIN user_hidden_list AS uh ON uh.est_id = tl.id
WHERE uh.userid = '1' AND uh.hidden = '1'");
How do I display all results expect those with a uh.userid = 1 and uh.hidden = 1
UPDATE: Tables
Table: user_hidden_list
userid | Hidden | est_id
---------------------------
1 | 1 | 1
2 | 1 | 1
1 | 1 | 2
Table: theList
id | name | locale
------------------------
1 | Jacks | LDN
2 | MacD's | LDN
3 | BK | LDN
4 | Byron | LDN
So if I am logged in with and userid of:
1 I should see: BK and Byron.
2 I should see: MacD's, BK and Byron.
3 (or anything else) I should see: Jacks, MacD's, BK and Byron.
If i understood correctly, the table user_hidden_list mantains a relation between one user and the users he can't see. So for, example, user with id equal to 1 (matching on column userid) can't see users 1 and 2 (matching on column est_id).
So, for a particular user with ID = X, we can get the ID list of user he can't see like next:
SELECT
est_id
FROM
user_hidden_list
WHERE
userid = X AND hidden = 1;
Using the previous query, we can get the visible users for user X like on next query:
SELECT
tl.id, tl.name, tl.locale
FROM
theList AS tl
WHERE
tl.id NOT IN (SELECT est_id
FROM user_hidden_list
WHERE userid = X AND hidden = 1);
I'm sure there will be a better (elegant) way to do this, but i'm just leaving work and my mind is not working nice now.
I am trying to display all results except where in Table 2 both the userid column equals 1 and the hidden column equals 1.
This does not suggest an outer join. You seem to want:
SELECT tl.id, tl.name, tl.locale, uh.hidden
FROM theList tl JOIN
user_hidden_list uh
ON uh.est_id = tl.id
WHERE NOT (uh.userid = 1 AND uh.hidden = 1);
I am guessing that userid and hidden are numbers of some sort, so I removed the single quotes. If they are really strings, then use the single quotes.
This also assumes that these values cannot be NULL. If that is a possibility, then the logic can be adjusted (using the null-safe comparator <=>).
Try out this, with even parantheses:
SELECT tl.id, tl.name, tl.locale, uh.hidden
FROM theList tl JOIN
user_hidden_list uh
ON uh.est_id = tl.id
WHERE (uh.userid <> 1 AND uh.hidden <> 1);
I have two tables that hold information about a drawing that I join in my query. The first table contains the drawings unique number, title and who it was drawn by. The second table contains the revision and the date the drawing was revised.
Table 1
|dwg_id|project_no|sws_dwg_no|dwg_title|dwg_by|
|1 |153 |153-100 |Pipe... |JS |
Table 2
|dwg_id|dwg_rev|dwg_date |rev_id|
|1 |A |2015-07-15 11:00:00 |1 |
|1 |B |2015-07-23 12:00:00 |2 |
|1 |C |2015-08-06 10:00:00 |3 |
I want join the two tables and only show the most recent revision change for a drawing.
This is my current query.
SELECT
`drawings`.`dwg_id`,
`project_no`,
`sws_dwg_no`,
`client_dwg_no`,
`dwg_title`,
`dwg_by`,
`dwg_rev`.`dwg_rev`,
`dwg_rev`.`dwg_date`,
MAX(`dwg_rev`.`dwg_rev`) AS dwg_rev
FROM
(`drawings`)
JOIN `dwg_rev` ON `drawings`.`dwg_id` = `dwg_rev`.`dwg_id`
WHERE
`project_no` = '153'
GROUP BY
`sws_dwg_no`,
`dwg_rev`.`dwg_rev`
ORDER BY
`dwg_rev`.`dwg_date` ASC,
`dwg_rev`.`dwg_rev` ASC
The results that this query returns doesn't contain the latest revision numbers or it returns all the revision for each drawing.
You can use the following query:
SELECT d.*, dr.*
FROM drawings AS d
INNER JOIN (
SELECT dwg_id, MAX(rev_id) AS maxRevId
FROM dwg_rev
GROUP BY dwg_id
) AS t ON d.dwg_id = t.dwg_id
INNER JOIN dwg_rev AS dr ON t.dwg_id = dr.dwg_id AND t.maxRevId = dr.rev_id
WHERE project_no = 153
The key point in the above query is the usage of a derived table that returns the latest revision, i.e. MAX(rev_id), per dwg_id. Using an INNER JOIN on that derived table you get back exactly this row out of dwg_rev table.
Using something like the above is necessary if you have multiple dwg_id per project_no. In this case, the above query will fetch the most recent revision per drawing for project_no = 153.
Demo here
Sometimes MAX isn't the best way to go, instead use LIMIT Try this:
SELECT
`drawings`.`dwg_id`,
`project_no`,
`sws_dwg_no`,
`client_dwg_no`,
`dwg_title`,
`dwg_by`,
`dwg_rev`.`dwg_rev`,
`dwg_rev`.`dwg_date`,
`dwg_rev`.`dwg_rev` AS dwg_rev
FROM
(`drawings`)
JOIN `dwg_rev` ON `drawings`.`dwg_id` = `dwg_rev`.`dwg_id`
WHERE
`project_no` = '153'
GROUP BY
`sws_dwg_no`,
`dwg_rev`.`dwg_rev`
ORDER BY
`dwg_rev`.`dwg_date` DESC,
`dwg_rev`.`dwg_rev` DESC
LIMIT 1;
If you need the latest revision you should order DESC check code below.
and also you can order only by dwg_rev.rev_id` DESC , if this rev_id is populated.
SELECT
drawings.dwg_id,
project_no,
sws_dwg_no,
client_dwg_no,
dwg_title,
dwg_by,
dwg_rev.dwg_rev,
dwg_rev.dwg_date,
MAX(dwg_rev.dwg_rev) AS dwg_rev
FROM
(drawings)
JOINdwg_revONdrawings.dwg_id=dwg_rev.dwg_id
WHERE
project_no= '153'
GROUP BY
sws_dwg_no,
dwg_rev.dwg_rev
ORDER BY
dwg_rev.dwg_dateDESC,
dwg_rev.dwg_revDESC
LIMIT 1;
I m trying to create ID like "A1 , A2, A3 .. etc
So i tried like this
$q = mysql_query("SELECT merge_id FROM merge_info ORDER BY merge_id DESC LIMIT 1;");
$s = mysql_fetch_array($q);
$merge_id5 = $s['merge_id'];
$count2=mysql_num_rows($q);
if($count2>0)
{
$merge_id5 = explode("A",$merge_id5);
$mergeid_no = $merge_id5[1]+1;
$merge_id6 = $mergeid_no;
}
else
{
$merge_id6 ="1";
}
if($count<1)
{
$merge_id = $merge_id5;
}
Everything is working fine... but after creating A9, it create A10 then again it creates A10 not moving to A11 , A12 . etc., i think if i write correct query to fetch last inserted row i'll fix this issue
Please someone help me
db table :
merge_id | name |
A1 | xxxx |
A2 | yyyy |
A3 | zzzz |
....
....
A9 | sds |
A10 | dsfs |
i know it is not the best solution to your problem, but this will help you.
and just get the first record because if i add LIMIT 1 the output is wrong :(
SELECT * FROM merge_info ORDER BY LENGTH(merge_id) DESC
Change your query to:-
SELECT MAX(merge_id) FROM merge_info;
I think it's better you use an auto_increment field, to get the last insert row with LAST_INSERT_ID(), otherwise you can't be sure if the last row, the one you have inserted.
So long. To order with your solution, use this.
ORDER BY SUBSTRING(merge_id,2) DESC
Better approach to your problem could be ,
use AUTO_INCREMENT field and while displaying append 'A' to it.
Now to solve this you can use below SQL statement
SELECT * FROM `merge_info` ORDER BY SUBSTRING(merge_id,2) DESC limit 1
should change you merge_id column into auto increment column,and the change your query into below mentioned,
SELECT MAX(merge_id) FROM merge_info;
if you want id like A1,A2,A3 ... then you can use the below code for get it
$q = mysql_query("SELECT merge_id FROM merge_info ORDER BY merge_id DESC LIMIT 1;");
$s = mysql_fetch_array($q);
$merge_id5 = $s['merge_id'];
$count2=mysql_num_rows($q);
$merge_id="A".$merge_id5;
after above process,noe we have a meger_id like A1,A2.. on application side
I have a query as follow: (shows are a table with tv shows and IMDB ID and recommended_titles is a table with two columns with IMDB_ID)
Select t2.* from shows t, shows t2, recommended_titles WHERE
t.imdb_id = recommended_titles. title_id_1
AND recommended_titles.title_id_2=t2.imdb_id
AND t.imdb_id = 0367279 LIMIT 7
The query is fine but I realized that it was only checking in the first column for my imdb id when it can also appear in my second one.
So i try to add the following:
OR
recommended_titles.title_id_2=t.imdb_id
AND t.imdb_id = recommended_titles. title_id_1
AND t.imdb_id = 0367279 LIMIT 7
But apparently OR can't be used with AND,
any suggestions as how I should do this ?
Edit:
To explain what I'm trying to do, here's a quick example in case my explanations above are too confusing.
table shows has rows like this:
name of a tv show | 00001
name of another | 00002
name of another | 00003
table recommended titles has (notice that an ID can be in either column)
00001 | 00002
00002 | 00003
You may look at operator precedence in mysql (and see that AND has an higher precedence than OR), or use parenthesis (much easier to use and maintain)
(t.imdb_id = recommended_titles.title_id_1 OR
recommended_titles.title_id_2=t.imdb_id)
AND recommended_titles.title_id_2=t2.imdb_id
AND t.imdb_id = 0367279 LIMIT 7
Do it like this,
(recommended_titles.title_id_2=t.imdb_id
OR t.imdb_id = recommended_titles. title_id_1)
AND t.imdb_id = 0367279 LIMIT 7
(t.imdb_id = recommended_titles. title_id_1
OR recommended_titles.title_id_2=t.imdb_id )
AND t.imdb_id = 0367279 LIMIT 7
Just use parenthesis to group your conditions for priorities.
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)