I have two tables
one is keywords [id | keyword | account] k
and one is templateKeywordLink [templateId | keywordId] tkl
What I want to do is get a result set with all keywords from the keywords table (where account = 1)
I also want to add another column called selected.
if k.id in (select templateId from templateKeywordLink) then selected should contain "selected". else it should be null
Im wondering what the optimal query is to do this?
There are several ways to do this. One way is to do a left join against a query that returns the IDs of interest.
Note that most databases have more compact ways to do what I did with a CASE statement, but CASE is portable to any relational database you could want to use.
SELECT k.*
, CASE
WHEN tkl.id IS NULL
THEN NULL
ELSE 'selected'
END as selected
FROM keywords k
LEFT JOIN (
SELECT DISTINCT templateId
FROM templateKeywordLink
) as tkl
ON k.id = tkl.templateId
Related
I have 3 tables that I am using and need to make a query to return data from one table based on the value of a single column in the second table.
tbl_user
ID
login
pass
active
mscID
tbl_master
ID
name
training_date
MSCUnit
Active
tbl_msc
mscID
mscName
my current SQL statement:
SELECT
tbl_master.ID,
tbl_master.name,
tbl_master.training_date,
tbl_master.MSCUnit,
tbl_master.active,
tbl_user.mscID
FROM
tbl_master,
tbl_user
WHERE
tbl_master.active = 1 AND tbl_master.MSCUnit = tbl_user.mscID
The values stored in tbl_msc.mscID is a varchar(11) and it contains a string similar to A00 or A19. This is also the Primary key in the table.
The values stored in tbl_user.mscID matches that of tbl_msc.mscID. The values stored in tbl_master.UnitMSC also matches that of tbl_msc.mscID.
My goal is to return all records from tbl_master where the currently logged in user has the same mscID. The problem I am having is the statement returns all records in tbl_master.
I have tried several different join statements and for some reason, I cannot get this to filter correctly.
I am missing something. Any assistance in the SQL statement would be appreciated.
Thanks,
Will
You should be writing this using joins. I don't know how you know who the current user is, but the idea is to join the three tables together:
SELECT m.ID, m.name, m.training_date, m.MSCUnit, m.active,
u.mscID
FROM tbl_master m JOIN
tbl_user u
ON m.MSCUnit = u.mscID JOIN
tbl_msc msc
ON msc.mscID = u.msc_ID
WHERE m.active = 1 AND msc.mscName = ?;
Notice the use of proper, explicit, standard JOIN syntax and table aliases.
Select a.*, b.userid from
table_master a, table_user b where
a.mscunit in (select mscid from
table_user where active=1)
This should point you in the right direction.
The query below gives me 2 out of the 3 answers I'm looking for. On the sub-query select I get null instead of no
the 3 possible values for column name isCyl could be blank, yes, no
I'm not sure if the sub-query is the best way to go about it, but I don't know how else to re-state the query.
The schedule table has a series of columns to show what tasks must be completed on an assignment. Related tables store the results of the tasks if they were assigned to be completed. So I need to test if a specific task was scheduled. If so, then I need to see if the results of the task have been recorded in the related table. For brevity I am only showing one of the columns here.
SELECT s.`reckey`,
if(s.cylinders="T",
(select
if(c.areckey is not null,
"yes",
"no"
)
from cylinders c where c.areckey = s.reckey limit 1
)
,""
) as isCyl
from schedule s
where s.assignmentDate between 20161015 and 20161016
order by s.reckey
Use a LEFT JOIN, which returns NULL for columns in the child table when there's no match.
SELECT s.reckey, IF(s.cylinders = "T",
IF(c.areckey IS NOT NULL, 'yes', 'no'),
"") AS isCyl
FROM schedule AS s
LEFT JOIN cylinders AS c ON c.areckey = s.reckey
WHERE s.assignmentDate between 20161015 and 20161016
ORDER BY s.reckey
If there can be multiple rows in cylinders with the same areckey, change it to:
LEFT JOIN (select distinct areckey FROM cylinders) AS c on c.areckey = s.reckey
or use SELECT DISTINCT in the main query.
I have three tables and their structure are below.
In keyword table I have unique keywords. A keyword has more than one user or domain_id so I have keyword_user table.
In rank table I have some numbers related to keywords.
I want to return all keywords related with my selected domain_id.
My conditions are:
Must: return min(rank_position) from rank table
Must: rank.rank_date = keyword.keyword_last_date
Problem is:
If I write keyword_user.domain_id = 1234 it returns all rows from keyword table but rank results are incorrect.
If I write rank.domain_id it returns only rows that related with keyword_last_date normally.
using min(rank_position) on SELECT causing wrong results.
I want all keywords from keyword table where keyword_user.domain_id = XXX and rank_date = keyword.keyword_last_date. Domain must my domain id not anything else.
SELECT rank.rank_id
, keyword_name
, keyword_last_date
, MIN(rank_position) my_rank
, rank_url
, rank.domain_id
FROM keyword
LEFT
JOIN keyword_user
ON keyword.keyword_id = keyword_user.keyword_id
LEFT
JOIN rank
ON keyword.keyword_id = rank.keyword_id
WHERE keyword_user.domain_id = 8262
AND rank.domain_id = 8262
AND rank_date = keyword.keyword_last_date
GROUP
BY keyword.keyword_name
ORDER
BY rakip_rank
As you can see from picture. domain_id column has different values but I have domain_id = 8262. They are not related to my expected result. Also my_rank column should different values not only "1".
TABLE: keyword
TABLE: rank
TABLE: keyword_user
I have a table
form (
int id )
webformsystemflags ( int id, int formid int sysflagid )
sysflag ( int id, name char(10) )
form table is a table which has all the forms
webform is a table which has the forms which have flags applied to it. It has a foreign key formid which is id to the form table and sysflagid which is foreign key to the sys flag table
sys flag is the table which contains the flags. Lets say I have flags defined as 1,2,3
I can have forms which don't have all the flags applied to it, some may have 1, some may have 2 or some may have 3 applied to it or some may have none.
How can I find all the forms which have either flag 1 or flag 2 or flag 3 applied to it ?
This is a common trick to find EXCLUSION. The value I have below of "FlagYouAreExpectingTo_NOT_Exist" is explicitly the one you expect NOT to be there. Here's how it works.
Get every form and LEFT JOIN to the Web System Flags table WITH FINDING the matching form, and flag setting you DO NOT want. If it finds a valid entry for the form and flag, the "formid" in the (wsf) table will exist. So, we want all that DON'T exist, hence the closing WHERE wsf.formid is null.
It will be NULL for those where it is NOT already flagged.
select
f.ID
from
forms f
left join webformsystemflags wsf
on f.id = wsf.formid
AND wsf.sysflagid = FlagYouAreExpectingTo__NOT__Exist
where
wsf.formid is null
You could use a subquery:
SELECT * FROM `form` WHERE `id` IN (SELECT `formid` FROM `webformsystemflags`)
Careful with subqueries on huge databases though. You could do the same thing with joins but this is an easy solution that will get you going.
Or for all results that DO NOT have a certain flag:
SELECT * FROM `form` WHERE `id` IN (SELECT `formid` FROM `webformsystemflags` WHERE `sysflagid` != 1 OR `sysflagid` != 2)
or a join method:
SELECT f.*, r.`sysflagid` FROM `form` f LEFT JOIN `webformsystemflags` r ON r.`formid` = f.`id` WHERE r.`sysflagid` != null
will get you the forms and the related flags. However, it will not get ALL flags in one row if the form has multiple flags on it. That one you may need to do a concat on the flags, but this answer is already growing unnecessarily complex.
*LAST EDIT *
Ok nutsandbolts - You need to update your question cause the two of us have overshot ourselves in a number of different queries and it isn't really helping to come back saying it doesnt give the right results. The right results can easily be reached by simply examining the queries we have provided and using the general logic behind them to compose the query that is right for you.
So my last suggestion - you say you want a query that will return a form IF it has a certain flag applied to it AND that is does NOT have other flags applied to it.
Here it is supposing you wanted all forms with a flag of 1 AND NOT 2 or 3 or none:
SELECT f.*, r.`sysflagid` FROM `form` f LEFT JOIN `webformsystemflags` r ON r.`formid` = f.`id` WHERE r.`sysflagid` =1 AND r.`formid` NOT IN (SELECT `formid` FROM `webformsystemflags` WHERE `sysflagid` = 2 OR `sysflagid` = 3)
Because your webformsystemflags is relational this query will NOT return any forms that do not exist in the webformsystemflags table - so you don't need to consider null.
If this is not what you're looking for I strongly suggest you rewrite your question with absolute and perfect clarity on your needs cause after this one I'm out of this conversation. Much luck to you though. Have fun.
You can use an exists clause to pull records like this:
select a.*
from form a
where exists (select 1
from webformsystemflags
where formid = a.id
and sysflagid IN (1,2,3))
This won't give you the associated flag. If you want that:
select a.*, b.sysflagid
from form a
join (select formid, sysflagid
from webformsystemflags
where sysflagid in (1,2,3)) b
on a.id = b.formid
There are many different ways to solve this.
EDIT: By reading a comment on the other answer it seems the question was unclear. You want the result forms that only have ONE flag? i.e. the form has flag 1 but not 2 or 3?
edit2: if you really just want a true/false query pulling only the true (has a flag):
select a.*, b.sysflagid
from form a
join webformsystemflags b on a.id = b.formid
If you want forms without flags:
select a.*
from form a
left join webformsystemflags b on a.id = b.formid
where b.formid is null
edit3: Based on comment, forms with one flag and not one of the others:
select a.*
from form a
where exists (select 1 from webformsystemflags where formid = a.id and sysflagid = 1)
and (
not exists (select 1 from webformsystemflags where formid = a.id and sysflagid = 2)
or
not exists (select 1 from webformsystemflags where formid = a.id and sysflagid = 3)
)
I am writing a SQL query that I would like to add a column to the recordset which has a value based on the existence of a record in another table. I have a left join joining the tables, and I am assuming I have to do some sort of pivot in my SQL, but I am not familiar with table pivoting.
My existing SQL is
SELECT tabs.name,tabs.id AS tabid,tabs.sort,fields.id AS fieldid, fields.label
FROM tabs
INNER JOIN fields
ON tabs.id = fields.tabid
LEFT JOIN fields_reports
ON fields_reports.fieldid = fields.id
WHERE fields_reports.reportid = 57
GROUP BY fields.id
ORDER BY tabs.sort, fields.id
What happened in the SQL is that it pulls field (which is the core of the statement) and the tabs (which are essentailly categories). The fields_reports table maps fields to reports that I am building.
What I need to do is add a column to my statement that says: if the current field has a record in the fields_reports table with the report number passed in (57) then assign the column value of 1, else 0.
Edit: I have another issue with the query. Right now the query is only pulling fields attached to one report. Instead of using a case is there a way that I can do a subquery to select from the fields_reports table so that I can pull all fields and then have the column attaching it to a report?
This is the query that pulls the records now, but only pulls one reports fields
SELECT tabs.name,tabs.id AS tabid,tabs.sort,fields.id AS fieldid, fields.label,
CASE WHEN fields_reports.id IS null THEN 0 ELSE 1 END AS inReport
FROM fields
INNER JOIN tabs
ON tabs.id = fields.tabid
LEFT JOIN fields_reports
ON fields_reports.fieldid = fields.id
WHERE fields_reports.reportid = 57
GROUP BY fields.id
ORDER BY tabs.sort, fields.id
Let me know if I should open up a new question for this.
You can `SELECT ..., IF(field_reports.reportid=57),1,0), ... FROM ...`
EDIT The test on reportid in the WHERE clause will need to be removed, or else this makes little sense as a solution. (Thanks to #Dave Long for this.)
Look what I've done to your script:
SELECT tabs.name,tabs.id AS tabid,tabs.sort,fields.id AS fieldid, fields.label
FROM tabs
INNER JOIN fields
ON tabs.id = fields.tabid
LEFT JOIN fields_reports
ON fields.id = fields.id AND fields_reports.reportid = 57
GROUP BY fields.id
ORDER BY tabs.sort, fields.id
Noticed something different? I dropped the WHERE clause and moved the condition to the ON clause of LEFT JOIN fields_reports. WHERE, as it was specified, turned your LEFT JOIN into INNER JOIN, so the result set would only try to select the rows with fields_reports.reportid = 57. If there were no such rows, none would be returned, i.e. that way you couldn't have your flag column working.
But now it can be defined, for example, like this:
MAX(CASE fields_reports.reportid WHEN 57 THEN 1 ELSE 0 END) AS TheFlagColumn
Just append it to your select list.
The phrase would be:
select ....
, case when LeftJoinedTable.column is null then 0 else 1 end
from ....
this works because, when you left join and no row exists in the joined table, the columns are still present in the result but they are all null. So you can test for this null value to see if you matched to a row in the right side of the join.