How to query for something that doesn't exist? - mysql

I am trying to query a sample database to look for sites without a domain.
We know which site a domain is associated with by domains.site = sites.id. There is no similar variable from site to domain.
So, I tried this (and a couple other joins / where filtering). Either, it's outputting about 50x the number of actual number of entries for either table, or it's outputting nothing. (This one's the former)
SELECT sites.name, domains.domain FROM sites
INNER JOIN domains
ON sites.id != domains.site
WHERE sites.is_deleted = 0 AND sites.id != domains.site
And this one's an example the latter, which outputs nothing
SELECT sites.name, domains.domain FROM sites
LEFT JOIN domains
ON sites.id != domains.site
WHERE sites.is_deleted = 0 AND site = NULL
I'm clearly missing something, to be able to go through the combinations, where only the site name and NULL are outputted (due to there being no domains associated with the site).
Of course, it could be a trick question, and there are simply no sites without domains.

For your kind of query you need to start with the query that should work if the data existed, using a LEFT JOIN, then add the condition that the data don't exist. So:
SELECT sites.name, domains.domain FROM sites
LEFT JOIN domains
ON sites.id = domains.site /* <--- this is where you got it wrong */
WHERE sites.is_deleted = 0
AND domains.site IS NULL;

Related

MYSQL Selecting specific rows or first row if doesn't exist

I have a table of texts from various dates. Each is indexed by service, variation, and page and sub-page ids.
I need to fetch all entries for a given service, page and sub-page. i.e. each variation! BUT If the particular specific subpage doesn't exist, I need it to fetch the first subpage for that page, rather than nothing for that variation.
This is my code -
SELECT * FROM frames f
LEFT JOIN varients v ON f.varient_id = v.varient_id AND f.service_id = v.service_id
ẀHERE f.service_id = :sid
AND f.frame_id = :fid
AND (f.subframe_id = :subid
OR f.subframe_id = (
select min(subframe_id) from frames ff
ẀHERE ff.service_id = f.service_id
AND ff.varient_id = f.varient_id AND ff.frame_id = f.frame_id
)
)
GROUP BY f.service_id, f.varient_id, f.frame_id
ORDER BY f.service_id, v.varient_date, f.frame_id, f.subframe_id
but as often as not this just gives the minimum rather than the specific, even when the specific value exists. I'm pretty sure that the OR isn't what I need..
I've tried working with UNION as per some other answers, but since I want more than a single result, I can't seem to work it out!
Thanks for any help ..
OK. I managed to achieve what I wanted. Two days of messing with this, and finally work it out after posting a question. I was helped by one of the 'related' questions, which whilst not giving me an answer, made me think about it a different way -
I basically turned the whole thing inside out: As i only wanted one result per variation, I used that as the primary table. Then Joined the 'frames' table twice, once for the specific value, and once for the first value (found using a search for MIN().) Used IFNULL to return the second record if the first wasn;t found. An extra IS NOT NULL check against the second record within the WHERE to avoid returning anything where there is nothing stored against the variation record.
SELECT v.service_id, v.varient_id, IFNULL(f.frame_id,ff.frame_id)as frame_id,
IFNULL(f.subframe_id,ff.subframe_id) as subframe_id , IFNULL(f.frameunique, ff.frameunique) as frameunique, IFNULL(f.frame_content,ff.frame_content) as framecontent
FROM varients v
LEFT JOIN `frames` f ON `f`.`varient_id` = `v`.`varient_id` AND `f`.`service_id` = `v`.`service_id` AND `f`.`frame_id` = 698 AND `f`.`subframe_id` = 0004
LEFT JOIN `frames` ff ON `ff`.`varient_id` = `v`.`varient_id` AND `ff`.`service_id` = `v`.`service_id` AND `ff`.`frame_id` = 698
AND `ff`.`subframe_id` = (select min(`subframe_id`) from `frames` `fff` where `fff`.`service_id` = `v`.`service_id`
AND `fff`.`varient_id` = `v`.`varient_id` AND `fff`.`frame_id` = 698 )
where `v`.`service_id` = 3 AND ff.frameunique IS NOT NULL
ORDER BY `f`.`service_id`, `v`.`varient_date`, `f`.`frame_id`, `f`.`subframe_id`
Posting this in case it helps anybody else. It still needs tidying but it works. Thanks for the comments. :)

SQL Is this Outer or Inner Join and how to join on Array

Seemed simple when I started and have done this before, now I confused myself and at a road block.
Have two tables: News_Table and a People_Table. Under the News_Table there is a field: News_People_Contributed and it has the ID's of the People_Table in array format (1,4,7,10) thus Four People contributed. I am creating a search parameter that looks up News_Header AND News_People_Contributed and can't figure how to create the search column.
News_Table
News_ID
News_Header
News_People_Contributed
People_Table
People_ID
People_First_Name...
Is it something like...
Select*
From News_Table
Left Join News_Table
On People_Table.People_ID IN (News_Table.News_People_Contributed)
Where Search_Param Like '%News_Header%' OR Search_Param Like '%People_First_Name%'
The problem is (News_Table.News_People_Contributed) is a string and the ID's are not. Plus I may not have people contributed etc. To make the issue even more complex, I'm doing this in MS Access instead of MySql, so have to code it "old school" sql for work around.
Perform a cross join and filter on matches in the string list. It says nothing about efficiency or form (as already commented on), but it works.
SELECT *
FROM News_Table, People_Table
WHERE InStr([News_People_Contributed],CStr([People_ID])) > 0;
This only answers part of the problem: The join -- the issue everyone seemed concerned about in the initial comments. There are not enough details about about the Search_Parameter to provide help on that. Supply more detail if you need more help there.

Access 'No Records Found' when Records Exist

I have a form in Access 2010 that's used as a search form to filter records matching specific criteria.
I transferred information in the backend from one set of tables to another. Now, the filter doesn't work. Even if I leave all the criteria blank - ie. set it to bring up all records - it tells me, 'No records found.'
I've remapped the tables a few times, made sure they all have information, and are linking and opening properly. What could be preventing Access from finding the records?
Here's the filter query, if it helps any. It doesn't appear to be filtering properly, even though it works fine with the old tables.
SELECT Activity.*, ActivityCash.*, EngSchDates.*, Monitoring.*, Procurement.*,
LookupDistrict.*
FROM ((((Activity LEFT JOIN LookupDistrict ON Activity.District =
LookupDistrict.District) INNER JOIN ActivityCash ON Activity.GWP = ActivityCash.GWP)
INNER JOIN EngSchDates ON Activity.GWP = EngSchDates.GWP)
INNER JOIN Procurement ON Activity.GWP = Procurement.GWP) INNER JOIN Monitoring ON
Activity.GWP = Monitoring.GWP ORDER BY Activity.District,
Activity.[ProgramYear], [Activity].GWP;
In general, to debug these types of problems, try removing one table at a time from the FROM clause (and SELECT) until you get your results back.
Remove AND [Activity].[Designer] like '*' from the query.

Web page linking to SQL2000 - taking too long to fully load

I have an internal web page that connects to an SQL2000 database, pulls the data and then displays it on a table. The SQL query takes on average 3 seconds to get the full results (in this instance 59 rows).
select Call_Ref, per_data7, dbo.dateonly(Scheduled_Date_Time) as sched_date, Call_Status_Description, Add1, Add2, Post_Code, contract_short_name, Call_Type_Description, LUCFC_Description, sched_colour_code
from Calls with (nolock)
inner join Clients with (nolock) on Link_to_Client=Client_Ref
left join Personnel with (nolock) on Last_Allocated_To=Pers_Ref
left join LU_Call_Types with (nolock) on Call_Type=Call_Type_Code
left join Personnel_More with (nolock) on Last_Allocated_To=PER_Link_to_Pers_Ref
left join LU_Call_Fault_codes with (nolock) on call_fault_code_1=LUCFC_Code
left join LU_Call_Status with (nolock) on Last_Event_Status=Call_Status_Code
left join call_more on call_ref=callm_link_to_call
left join contractids on link_to_contract_header=contract_ref
where dbo.dateonly(Scheduled_Date_Time) between '09/09/2013' and '13/09/2013'
and Call_Type in ('BC','IN')
and PER_Data7 in ('Team 1','Team 2','Team 3','Team 4','Team 5','Team 6','Team 7','Team 8','Team 9','Team 10','Gas1')
and Call_Status_Description in ('Allocated','Reported Done','Complete')
or CALLM_Data21 between '19/08/2013' and '23/08/2013'
and CALLM_Data22 in ('Team 1','Team 2','Team 3','Team 4','Team 5','Team 6','Team 7','Team 8','Team 9','Team 10','Gas1')
and link_to_contract_header = 'BGAS-1'
and call_type not in ('BC','IN')
and call_status_description not in ('Cancelled')
order by per_data7, dbo.dateonly(Scheduled_Date_Time)
I am then displaying those results in a table, using do/while loops and if statements to filter the results into where they should be displayed in the table - the problem is that each of those takes an additional 3 seconds to display - thus the complete web page takes around 3 and half minutes to fully load (i had to extend the timeout to allow to fully load).
I need to get this down to a usable amount of time.
The webserver is Windows IIS and the web page is basic html, classic-asp with some VB.
It server also has PHP installed, but i am not sure which version.
I have attached the files in a ZIP for anyone to look at.
https://www.dropbox.com/s/qbfp0cswo403e4u/files.zip
So, guys.... what can I do to get this page to load in a timescale that makes it actually usable?
A viewable version of the page is here http://195.171.121.111/week0909-test.asp which I will leave there for a day or so.
The user defined function function in the where and order by clause is probably causing the slow-down for SQL.
You should be able to pull the query data once, and then build up in memory hashes of the Teams and Dates. Another hash should contain lists of the entries for a cross hash between the team and dates, then you can just iterate over the data set once instead of (team-names.count * dates.count) times.

database structure for google plus circles?

I know for sure that Google does not use mysql, but in my case I happen to work on a project using mysql and has features that are very similar to circles:
user can belong to many circles
user can be add/removed from circles
posts can be public or can be shared to circles/individual users
if a post is shared to a circle, and new user is added to this circle then this user can also view the post.
If a post is shared to a circle, and an user is removed from this circle then: a. he/she can still view the post if he/she replied in the post b. he/she cannot view the post anymore otherwise
As you can already see, with the above requirements there are a lot going on in the database. If I really share both to circles and individual users, i will probably need 2 One2Many tables. If I share only to individual users by getting the list of users for each circle at the very beginning, then I run into troubles later on when users edit these circles.
Currently, my get-around hack is to share to circles only, even for each individual user I create a 1 user only circle.
So my current database tables look a bit like this:
circle_to_user:
id
circle_id
user_id
friend_id
post:
id
user_id
is_public
post_to_circle
id
post_id
circle_id
To query out the list of posts a user can view, the query is rather complicated and consists of multiple joins:
$q = Doctrine_Query::create()
->addSelect('s.*')
->addSelect('u.id, u.first_name, u.last_name, u.username, u.avatar')
->from('UserStatus s')
->leftJoin('s.User u')
->orderBy('s.created_at DESC');
$userId = sfContext::getInstance()->getUser()->getUserId();
if ($userId == $viewUserId) {
$q->orWhere('s.user_id = ?', $userId);
$q->orWhere('s.user_id IN (SELECT DISTINCT cu1.friend_id FROM CircleUser cu1 WHERE cu1.user_id = ?) AND s.is_public = ?', array($userId, true));
$q->orWhere('s.id IN (SELECT DISTINCT(us2.id)
FROM
UserStatus us2 INNER JOIN us2.UserStatusCircles usc2 ON usc2.user_status_id = us2.id
INNER JOIN usc2.Circle c2 ON c2.id = usc2.circle_id
INNER JOIN c2.CircleUsers cu2 ON cu2.circle_id = c2.id AND cu2.friend_id = ?)', $userId);
} else {
$q->orWhere('s.user_id = ? AND s.is_public = ?', array($viewUserId, true));
$q->orWhere('s.id IN (SELECT DISTINCT(us1.id)
FROM
UserStatus us1 INNER JOIN us1.UserStatusCircles usc1 ON usc1.user_status_id = us1.id AND us1.user_id = ?
INNER JOIN usc1.Circle c1 ON c1.id = usc1.circle_id
INNER JOIN c1.CircleUsers cu1 ON cu1.circle_id = c1.id AND cu1.friend_id = ?)', array($viewUserId, $userId));
$q->orWhere('s.id IN (SELECT DISTINCT(us2.id)
FROM
UserStatus us2 INNER JOIN us2.UserStatusCircles usc2 ON usc2.user_status_id = us2.id AND us2.user_id = ?
INNER JOIN usc2.Circle c2 ON c2.id = usc2.circle_id
INNER JOIN c2.CircleUsers cu2 ON cu2.circle_id = c2.id AND cu2.friend_id = ?)', array($userId, $viewUserId));
}
I hope that the above info is not too long, I just want to give lots of details. My questions are:
Given the above requirements, is my implementation good enough, or is there anything I should change to make it better?
I want to search for articles regarding this type of specific database design problem but could not find much, is there any technical term for this type of database design
Would you suggest any alternatives such as using another type of database, or perhaps index the posts with a searchengine like elastic and let it handle the search instead of using mysql?
Thank you very much for reading until this point, if you find anything I should change in the question to make it easier to follow and to answer, please do let me know.
while your single user circle sounds like a nice try, how will you go about distinguishing it on the way out? when you see a post is shared to a circle, how do you know if that circle is a genuine one or a single user? because i imagine you want to display them differently on the interface. and you'd probably need to know when you fetch the fake circles from the db that the user should not be able to edit them.
while you might get away with avoiding linking to users you now have to handle special circle cases. i'd say go with your 2 x 1-* tables that link a post to multiple circles and separately to multiple users.
perhaps to encourage you to review your intention and leaving aside the 'friend' relationship that may add a special case, as i see it you're more or less looking to: fetch all posts that are public, or are shared with my user, or are shared with a circle i am in, or are posts that i replied to. that isn't too complicated i don't think and you don't have to get a list at the beginning or anything.
(on a related note, multiple JOINs is not a problem that stands out. more importantly you have multiple sub-queries. usually that is bad news. in most cases they can be reworked as normal joins and usually more cleanly).
This kind of problem is mostly not solved with a relational model , i think google uses the datastore , which then sits on bigtable , cassandra and hadoop equivalent.
I am also in same problem but i can suggest you something that i allready covered/completed that dont make two tables for post instead of that add column in Posts table named with/circle_id.
And i also i want to tell you that add a/or more default circle entry(specifically Public and also All Friends/Circles in Circles table.
Now your Post Pickup query will be like this.
$id=$_SESSION["loged_in_user_id"];
$sql="SELECT * FROM `posts` as p,`circles` as c WHERE c.circle_create_id=$id and (p.with=c.id or p.with=1)";//p.with columns contain circle id and as i tell first entry will be public
$sql_fier=mysqli_query($sql);
/*-------I think you know how to manipulate fetched data---------*/
Connect me on social network http://www.funnenjoy.com (signup/login is required )