SQL Joining Diffrent Size Tables Together With Null Value Replacement - mysql

I am working on a query for a datatable and I can't seem to get it to display how I want, I don't know if this is even possible in SQL What I am looking to do is get a query to respond with ideally an extra column of Boolean type.
Currently I can run two queries and they both work perfectly but I can't work out how to join them together bellow is the code from my first query what this does is return beers a user has tried this works fine and as expected and returns as expected.
SELECT *
FROM keg.beer
JOIN keg.userbeer
ON beer.id = userbeer.beer_id
WHERE userbeer.username_id = 1;
The second query is even simpler and is just a select getting the list of beers.
SELECT * FROM keg.beer
What I want to do is run a query and have it return a list of beers with a Boolean value if the user has tried it or not.

You're not going to run into too many scenarios for "Desired Results" that can't be produced with plain 'ol SQL. In this case you'll use a CASE statement to determine if the person has tried a beer. You'll also want a LEFT OUTER JOIN so you don't drop records coming from your beer table when your filtered userid doesn't have a userbeer record for that beer:
SELECT
beer.name,
beer.id,
beer.country,
CASE WHEN userbeer.username_id IS NULL THEN 0 ELSE 1 END AS user_tried_beer_boolean
FROM keg.beer
LEFT OUTER JOIN keg.userbeer
ON beer.id = userbeer.beer_id
AND userbeer.username_id = 1;
As #SeanLange mentioned in the comments here, the restriction of the WHERE statement for the userid would cause records to be dropped that you want in your result set, so we move the restriction of username_id = 1 to the ON portion of the LEFT OUTER JOIN so that the userbeer table results are restricted to just that user before it's joined to the beer table.
Now I need a drink.

SELECT b.id,
b.name,
CASE WHEN u.username_id IS NOT NULL THEN TRUE ELSE FALSE END AS userdrankbeer
FROM keg.beer b
LEFT JOIN ( SELECT * FROM keg.userbeer WHERE username_id = 1 ) u
ON beer.id = userbeer.beer_id
;

Related

SQL IF ELSE WITH MULTIPLE SELECT STATEMENT

I want to optimize these SQL queries using if-else but how I should use it? .
if this query result contain 'ALL'
SELECT
bdsubcategory.subcategoryID as ID,
bdsubcategory.subcategoryName as Name
FROM
phonebook.newsms_subscription
INNER JOIN bdsubcategory ON bdsubcategory.subcategoryID = newsms_subscription.subcategoryID
INNER JOIN newsms_client ON newsms_subscription.clientID =newsms_client.clientID
INNER JOIN newsms_person ON newsms_subscription.personID = newsms_person.personID
WHERE
newsms_subscription.isActive = 1 AND
newsms_person.personID = '856'
Then i want to query this
SELECT
bdsubcategory.subcategoryID as ID,
bdsubcategory.subcategoryName as Name
FROM
phonebook.newsms_subscription
INNER JOIN bdsubcategory ON bdsubcategory.subcategoryID = newsms_subscription.subcategoryID
INNER JOIN newsms_person ON newsms_subscription.personID = newsms_person.personID
WHERE
newsms_subscription.isActive = 1
GROUP BY subcategoryName
ORDER BY subcategoryName
otherwise take query1 result .
The problem is that if we do not refactor your project, then you always have to evaluate query1 and see whether it contains All or not. If it does not contain All, then you need to evaluate query2 as well. This can hardly be optimized, let's see a few approaches:
Quickening query1
Since All might be not be the very last evaluated element, adding it to the filter and limiting it is a good idea to quicken query1:
SELECT
COUNT(*)
FROM
phonebook.newsms_subscription
INNER JOIN bdsubcategory ON bdsubcategory.subcategoryID = newsms_subscription.subcategoryID
INNER JOIN newsms_client ON newsms_subscription.clientID =newsms_client.clientID
INNER JOIN newsms_person ON newsms_subscription.personID = newsms_person.personID
WHERE
newsms_subscription.isActive = 1 AND
newsms_person.personID = '856' AND
bdsubcategory.subcategoryName = 'ALL'
LIMIT 0, 1
So, you could create a stored procedure which evaluates query1' (query1' is the quickened version of query1, as seen above) and if there is a result, then we need to execute query1. Otherwise we need to execute query2. This way you still execute two queries, but the first query is optimized.
Refactoring
Note that the second query does not change. You could create a table where you could cache its results, using a periodic job. Then, you could skip the second table to
SELECT ID, Name
FROM MyNewTable;
without the many joins. You would also cache the results of the first query into a table where the items having ALL would be stored and query that table.
One option would be to use a CASE.
Change this:
newsms_person.personID = '856'
To this:
'Y' = CASE WHEN UPPER('856') = 'ALL' THEN 'Y'
WHEN newsms_person.personID = '856' THEN 'Y'
ELSE 'N' END
Alternatively, a stored procedure could be used to first validate whether the personID seems valid, then returns the appropriate data.

SQL Query seems not to affect the same number of rows, Adding a count statement

I have made a query that looks like this
Query 1.
SELECT zlec_status.nazwa AS Status,
piorytet.nazwa AS Priorytet,
Concat(koord.imie, ' ', koord.nazwisko) AS `Koordynator`,
Concat(zlec_adresy.miasto, ' - ', zlec_adresy.ulica, ' ',
zlec_adresy.oddzial)
AS `adres`,
zlec_z_dnia,zlec_id,
zlec_nr,
zlec_do,
zlec_ogran,
awizacje,
awizacja_na_dzien,
termin_zamkniecia,
tresc,
uwagi
FROM zlec
INNER JOIN koord
ON zlec.koord = koord.id
INNER JOIN zlec_adresy
ON zlec.zlec_addres = zlec_adresy.id
INNER JOIN piorytet
ON zlec.priorytet = piorytet.id
INNER JOIN zlec_status
ON zlec.status_zlecenia = zlec_status.id
And the following one which is a ordinary one
Query 2.
SELECT * FROM zlec;
The thing is the first one returns ( affects by executing ) 48 rows where the second query returns 103 rows. What could be the possible cause of this?
I will also show you my dumb of the sql in case you would like to make a run on your own http://pastebin.com/cMPAtxCU .
Subquestion - quite no point starting of with a new question for that because its also connected with the row count affect.
Besides I was wondering how can I get into the first query a count(*) to get the affected rows - it has to be done in sql I cannot use php code for that, probably it would be good to use a limit 1 for the count.
With INNER JOIN, if one of your other tables, koord, zlec_adresy, piorytet and zlec_status is missing a record corresponding to a record in zlec, that record in zlec will not be in the result set. If you want every record in zlec to appear, you have to use LEFT JOIN. Check out:
http://blog.codinghorror.com/a-visual-explanation-of-sql-joins/
For a pretty good explanation.
With your additional inner joins rows might be eliminated. Have you tried adding the inner joins to your "Select * FROM zlec;"?

SQL - OutterApply and Left Join

I'm working with a large stored procedure, I'm having trouble with a small portion of it.
When I execute a query on the table im joining, there can be 0, 1 or 2 results. If there are 0 results, I don't really care, my code returns null values, no big deal. If there is 1 result, my code returns the correct values, however, if there are 2 results, I am having trouble selecting the second result.
My code below works until the second OutterApply(the AHM2 stuff). Does anyone see what I am doing wrong?
The animal ID is identical for both OuterApplys. I just need to return the second result, if there is one, and if it is not the same as the first one.
SELECT TOP 1
AHM.AnimalHerdManagementId,
AHM.HerdManagementId,
AHM2.AnimalHerdManagementId,
AHM2.HerdManagementId,
HM.Code AS HerdManagementCode,
HM2.Code AS HerdManagementCode2
OUTER APPLY
(
SELECT TOP 1 AHM.AnimalHerdManagementId, AHM.HerdManagementId
FROM dbo.AnimalHerdManagement AHM
WHERE AHM.AnimalId = A.AnimalId AND ISNULL(AHM.EffectiveFrom, #EffectiveFrom) <= #EffectiveFrom
ORDER BY AHM.EffectiveFrom DESC
) AHM
LEFT JOIN dbo.HerdManagement HM ON AHM.HerdManagementId = HM.HerdManagementId
OUTER APPLY
(
SELECT TOP 1 AHM2.AnimalHerdManagementId, AHM2.HerdManagementId
FROM dbo.AnimalHerdManagement AHM2
WHERE AHM2.AnimalId = A.AnimalId AND AHM2.AnimalHerdManagementId != AHM.AnimalHerdManagementId AND ISNULL(AHM2.EffectiveFrom, #EffectiveFrom) <= #EffectiveFrom
ORDER BY AHM2.EffectiveFrom DESC
) AHM2
LEFT JOIN dbo.HerdManagement HM2 ON AHM2.HerdManagementId = HM2.HerdManagementId
I think I can help you with the OUTER APPLY but the method of getting the two different values is going to need some help as my solution is a total hack.
First, you don't need to join on the outer apply. The join is implied. So you can completely eliminate the join syntax from your query.
Second, AnimalHerdManagement looks/seems like a special table called a Junction Table. All the data contained in it is contained elsewhere (That it contains completely redundant data is why it's called a special table). But that is minor.
Finally, here is some example code I threw together that accomplishes what you are after. The method I am using to retrieve different results on the two outer apply's is a hack, but if you are sure that will always be true, it might work. I am not able to get a multi-level outer apply to work.
select * from AH_Animal A
outer apply
(
select max (HerdManagementID) as HerdMgmtID1 from AH_AnimalHerdManagement HM1 where HM1.AnimalID = A.AnimalID
) as z
outer apply
(
select min (HerdManagementID) as HerdMgmtID2 from AH_AnimalHerdManagement HM2 where HM2.AnimalID = A.AnimalID
) as zz
I hope that helped. There has to be another solution to this, as this would not work at all if you ever expected 3 results.
Query Results:

Compare query outputs

Query 1:
select name,trans from sids s where apt='KAUS';
Query 2:
SELECT id,transition_id from std_sid_leg where data_supplier='E' and airport='KAUS';
Values of name is same that of id and trans with transition_id.Result set 1 is subset of result set 2.Both the tables have common columns as apt=airport
If query alone couldnt work please provide any script.
I need to compare the outputs of these 2 queries and print the data differences.
Thank you.
You're looking for a combined left+right join.
This is called an full outer join (as opposed to a left/right outer join).
By selecting only the rows where join columns are null you'll get the mismatches; this is called an anti-join.
The full outer-anti-join looks like this:
select s.*, ssl.*
from sids s
outer join std_sid_leg ssl on (s.name = ssl.id and s.trans = ssl.transition_id)
where (s.name is null and s.trans is null)
or (ssl.id is null and ssl.transition_id is null)

Allowing Optional Parameters for MySQL Query

I have a search page that has multiple fields that are used to create a refined search. Every field is optional. I'm trying to start crafting my sql query so that it will work given the proper variables but I'm having trouble.
Here is the SQL query I currently have:
SELECT
indicator.indid,
indicator.indicator,
indtype.indtype,
provider.provider,
report.report,
actor.actor
FROM
actor,
indicator,
indtype,
report,
provider
WHERE
indicator.indtypeid = indtype.indtypeid
AND indicator.actorid = actor.actorid
AND indicator.reportid = report.reportid
AND report.providerid = provider.providerid
AND indicator.indicator LIKE '%$indicator%'
AND indicator.indtypeid = $indtypeid;
Whenever I provide an indicator and an indtypeid, the search works just fine. However, when I leave the indtypeid field blank, and have the variable set to * (as its default value), the query returns no results. I've tried playing with the query manually and it doesn't seem to like the * or a % sign. Basically, if only an indicator is specified and no indtypeid is specified, I want to return all indicators for all indtypeids.
I'm sure I'm missing something minor, but I would appreciate any assistance that could be provided. I may be going about this all wrong in the first place.
Try this instead:
SELECT i.indid, i.indicator, it.indtype,
p.provider, r.report, a.actor
FROM actor a
INNER JOIN indicator i ON a.actorid = i.actorid
INNER JOIN indtype it ON i.indtypeid = it.indtypeid
INNER JOIN report r ON i.reportid = r.reportid
INNER JOIN provider p ON r.providerid = p.providerid
WHERE 1 = 1
AND ($indicator IS NULL OR i.indicator LIKE '%$indicator%')
AND ($indtypeid IS NULL OR i.indtypeid = $indtypeid);
So if you pass a $indicator = NULL, then the first condition AND ($indicator IS NULL OR i.indicator LIKE '%$indicator%') will be ignored since it will resolve to True, and the same thing for the second condition.
I've removed other Where condition and replace them with JOINs, and for WHERE 1 = 1 to make the query work fine in case you pass the two variables $indicator and $indtypeid with NULL values for each, in this case it will return all results since 1 = 1 always true.