MySQL Join table and get results that don't exist in one - php

I have two tables, one that has a foreign key from the other. I want to get all records that don't exist in the foreign table, based on certain criteria.
Here are the tables I have:
item_setting
setting_id
category_id
item
item_id
setting_id
name
expired_dt
Here's the query I'm using now:
SELECT
iset.setting_id
FROM
item_settings iset
LEFT OUTER JOIN
item i ON i.setting_id = iset.setting_id
WHERE
iset.category_id = '5' AND i.setting_id is null
This query works in providing any setting_id's that do not have a record in the item's table within a specific category.
However, now I want to include cases where the expired_dt less than than time() (meaning it's past expired). In otherwords, I would think to add this:
WHERE
iset.category_id = '5' AND (i.setting_id is null OR i.expired_dt < '".time()."')
However, this doesn't work, it returns all the records.
Any suggestions? Maybe I'm completely over complicating this.... I just want to return the setting_id's from the item_settings table, where the expired_dt associated in the item table is expired or if it does not even exist in the item table.
Thank you!

Try moving the timestamp condition into the join clause. Something like
item_settings iset
LEFT OUTER JOIN
item i ON i.setting_id = iset.setting_id and i.expired_dt > time()

Related

Speed-up/Optimise MySQL statement - finding a new row that hasn't been selected before

First a bit of background about the tables & DB.
I have a MySQL db with a few tables in:
films:
Contains all film/series info with netflixid as a unique primary key.
users:
Contains user info "ratingid" is a unique primary key
rating:
Contains ALL user rating info, netflixid and a unique primary key of a compound "netflixid-userid"
This statement works:
SELECT *
FROM films
WHERE
INSTR(countrylist, 'GB')
AND films.netflixid NOT IN (SELECT netflixid FROM rating WHERE rating.userid = 1)
LIMIT 1
but it takes longer and longer to retrieve a new film record that you haven't rated. (currently at 6.8 seconds for around 2400 user ratings on an 8000 row film table)
First I thought it was the INSTR(countrylist, 'GB'), so I split them out into their own tinyint columns - made no difference.
I have tried NOT EXISTS as well, but the times are similar.
Any thoughts/ideas on how to select a new "unrated" row from films quickly?
Thanks!
Try just joining?
SELECT *
FROM films
LEFT JOIN rating on rating.ratingid=CONCAT(films.netflixid,'-',1)
WHERE
INSTR(countrylist, 'GB')
AND rating.pk IS NULL
LIMIT 1
Or doing the equivalent NOT EXISTS.
I would recommend not exists:
select *
from films f
where
instr(countrylist, 'GB')
and not exists (
select 1 from rating r where r.userid = 1 and f.netflixid = r.netflixid
)
This should take advantage of the primary key index of the rating table, so the subquery executes quickly.
That said, the instr() function in the outer query also represents a bottleneck. The database cannot take advantage of an index here, because of the function call: basically it needs to apply the computation to the whole table before it is able to filter. To avoid this, you would probably need to review your design: that is, have a separate table to represent the relationship between movies and countries, which each tuple on a separate row; then, you could use another exists subquery to filter on the country.
The INSTR(countrylist, 'GB') could be changed on countrylist = 'GB' or countrylist LIKE '%GB%' if the countrylist contains more than the country.
Then don't select all '*' if you need only some columns details. Depends on the number of columns, the query could be really slow

Laravel: When doing an LEFT JOIN how to make alias of fields so I can access fields with the same name

I have a "master" table, lets say is something like:
id autoincrement
name varchar(10)
category integer
Then I have a "detail" table, lets say:
id autoincrement
master_id integer
qty integer
I want to make a LEFT JOIN like:
SELECT * FROM master
LEFT JOIN detail ON master.id = detail.master_id
WHERE category=1
This query produces exactly what I want in SQL: A table with all the master records even if they don't have detail, in that case will get me the detail columns with NULL which is correct.
Now in Laravel, I want to do something like:
$records = Master::where('category', '=', 1)
->leftJoin('detail', 'master.id', '=', 'detail.master_id')
If the detail table is empty, it returns id as NULL
I think this is because it returns id twice, first the master.id, and then the second id which comes from the detail table, is, of course, NULL
So how can I alias the first (or second id) in order to access it?
You can get all the columns from the master table, and select and alias each of the details table columns that you need separately in a select. You are right that it overrides them because of the same names. So try this:
$records = Master::where('category', '=', 1)
->select('master.*', 'detail.id as detail_id')
->leftJoin('detail', 'master.id', '=', 'detail.master_id')
Keep in mind that this will just show the detail table ID in the results along with all the master table columns, you should add the other columns from the detail table as a select parameters.

Adding a Row into an alphabetically ordered SQL table

I have a SQL table with two columns:
'id' int Auto_Increment
instancename varchar
The current 114 rows are ordered alphabetically after instancename.
Now i want to insert a new row that fits into the order.
So say it starts with a 'B', it would be at around id 14 and therefore had to 'push down' all of the rows after id 14. How do i do this?
An SQL table is not inherently ordered! (It is just a set.) You would simply add the new row and view it using something like:
select instancename
from thetable
order by instancename;
I think you're going about this the wrong way. IDs shouldn't be changed. If you have tables that reference these IDs as foreign keys then the DBMS wouldn't let you change them, anyway.
Instead, if you need results from a specific query to be ordered alphabetically, tell SQL to order it for you:
SELECT * FROM table ORDER BY instancename
As an aside, sometimes you want something that can seemingly be a key (read- needs to be unique for each row) but does have to change from time to time (such as something like a SKU in a product table). This should not be the primary key for the same reason (there are undoubtedly other tables that may refer to these entries, each of which would also need to be updated).
Keeping this information distinct will help keep you and everyone else working on the project from going insane.
Try using an over and joining to self.
Update thetable
Set ID = r.ID
From thetable c Join
( Select instancename, Row_Number() Over(Order By instancename) As ID
From CollectionStatus) r On c.instancename= r.instancename
This should update the id column to the ordered number. You may have to disable it's identity first.

Need help in a sql query

I have a field that is a varchar that contain values such as (88,90,100,200) and i have another one contains the value 200 when using the IN clause to see if the second field in the first field it returns empty result but when comparing it with 88 it return results
So i was wondering what im doing wrong here and if there is a better way.
Here is the mysql code
select * from user inner join category where parent_id IN (categories)
parent_id is located in the category table and the categories in the user table
When you do a JOIN you need an ON clause to specify that you are looking for rows that somehow "match" across two tables. If you want all the rows from a single table where some column has a value that is "one of the values in this list..." you use IN. So these are both valid SQL:
SELECT * FROM user INNER JOIN category ON user.someColumn = category.someOtherColumn // can add WHERE clause
or
SELECT * FROM user WHERE parent_id IN (88, 99, 100, 200)
Can't tell you exactly what query you should use unless you share your table structures, as the question is unclear.

mysql join two tables likes and posts

Here is my php/MySQL task:
I have a table POSTS that contains num field that is the primary key and other information fields about the post (author, title, etc.). I also have a table LIKE that contains a userId field that is the primary key and a field POST that corresponds to the num field in posts. Given a specific userID, I need to get all of the rows from the POSTS table that the userId 'likes'.
Table 1 - posts
-num
-author
-title
Table 2 - likes
-userId
-postId
This is all in php so my first idea was to get all of the rows from the LIKES table where the userId matches the one given and store those rows in an array. Then I would iterate through the array and for each row I would search get the row of the POSTS table where postId=POSTS.num. However, this seems like it would be rather slow, especially since each iteration through the array would be a separate mysql query.
I am assuming there is a faster way. Would it be to use a temporary table or is there a better way to join the tables? I have to assume that both tables contain many rows. I am a mysql novice so if there is a better solution please explain why it is better. Thank you in advance for you help!
Try the following query:
SELECT
`posts`.*
FROM
`likes`
INNER JOIN
`posts` ON
`posts`.num = `likes`.postId
WHERE
`likes`.Userid = {insert user id here}
Depending on your schema (not sure if each record in 'likes' has to be unique, you may want to use the DISTINCT keyword on your select to filter out duplicates.
SELECT poli.* FROM (
SELECT po.* FROM posts po
JOIN likes li
ON li.postId = po.num
WHERE li.userId = '$yourGivenUserId'
) AS poli
$yourGivenUserId is the given userId.

Categories