Subtract two query results in mySQL - php

I have 2 queries which gives all records(including the booked ones) and gives out booked records only. I wanted to subtract the two tables so that it only shows the unbooked records, here are the example of the query results:
Query 1:
+--------+--------+
| Number | AreaNo |
+--------+--------+
| 6 | A |
| 6 | B |
| 6 | C |
| 7 | A |
| 7 | B |
+--------+--------+
Query 2:
+--------+--------+
| Number | AreaNo |
+--------+--------+
| 6 | B |
| 6 | C |
| 7 | B |
+--------+--------+
Desired Results:
+--------+--------+
| Number | AreaNo |
+--------+--------+
| 6 | A |
| 7 | A |
| 7 | C |
+--------+--------+
I know that I can't use MINUS in mySQL but I'm not sure that LEFT JOIN works in this situation. If this doesn't work, is it possible to work on the where clause?(Like if the number match, it only clear out the one with matching AreaNo). I tried this with two AND clause and it doesn't work. It clears out the results that doesnt fit either criteria. I have been doing researches over a week and nothing works. Please help, I am really desperated.
Query 1:
SELECT bookingListNo,
areaNo
FROM BookingList,
BookingArea,
BookingLocation
WHERE bookingListNo NOT IN (SELECT bookingListNo
FROM Booking
WHERE bookingAreaNo IS NULL) AND
BookingList.bookingLocationNo = BookingLocation.bookingLocationNo AND
BookingLocation.BookingLocationNo = BookingArea.bookingLocationNo
Query 2:
SELECT bookingListNo,
areaNo
FROM Booking,
BookingArea
WHERE Booking.bookingAreaNo = BookingArea.bookingAreaNo

This is how you do it.
SELECT Q1.Number,
Q1.AreaNo
FROM Query1 Q1
LEFT JOIN Query2 Q2
ON Q1.Number = Q2.Number AND
Q1.AreaNo = Q2.AreaNo
WHERE Q2.Number IS NULL AND
Q2.AreaNo IS NULL

LEFT OUTER JOIN will do the trick
SELECT *
FROM TABLE1 t_1 LEFT OUTER JOIN TABLE2 t_2
ON t_1.AreaNo = t_2.AreaNo ;

Check out this article for reference: http://www.sitepoint.com/understanding-sql-joins-mysql-database/
I'm guessing a RIGHT JOIN would do the trick.
Not exactly sure what your tables are like, but if you are joining a table with unbooked data to one that has all of our items, then you could do a query like this:
SELECT *
FROM all_items
RIGHT JOIN unbooked_data ON all_items.item_id = unbooked_data.item_id
When you RIGHT JOIN it only selects the items that are in the table you are joining on that have matches in the table being joined to. This should allow you to select unbooked data. If this doesn't fit your situation, including your queries in your question might help us answer your problem more directly.

mysql> SELECT tabl1.number,tabl1.areano FROM tabl1 LEFT JOIN tabl2 using(number,
areano) WHERE tabl2.number IS NULL; ;
+--------+--------+
| number | areano |
+--------+--------+
| 6 | A |
| 7 | A |
+--------+--------+

Related

Return all wows, mached and unmatched in MySQL Query

I have two tables and i'm like to query 2 tables to obtain a report.
POSITION
+-------------+---------------+
| position_id | position_name |
+-------------+---------------+
| 1 | E1P1 |
| 2 | E1P2 |
| 3 | E3P3 |
| 4 | E4P4 |
+-------------+---------------+
PEOPLE
+------------+-------------+--------------------+
| people_id | people_name | people_position_id |
+------------+-------------+--------------------+
| 1 | JOHN | 2 |
| 2 | MARK | 4 |
+------------+-------------+--------------------+
QUERY
SELECT position_id, position_name, people_name FROM position
RIGHT JOIN people ON people_position_id = position_id
When I use simple query I get only matched rows, ho to obtain all?
I'm like to obtain this result
+----+----------+--------+
| ID | POSITION | STATUS |
+----+----------+--------+
| 1 | E1P1 | Empty |
| 2 | E1P2 | JOHN |
| 3 | E3P3 | Empty |
| 4 | E4P4 | MARK |
+----+----------+--------+
I would use a left join here:
SELECT
po.position_id,
po.position_name,
COALESCE(pe.people_name, 'EMPTY') AS STATUS
FROM position po
LEFT JOIN people pe
ON po.position_id = pe.people_position_id;
By the way, the reason your current right join attempt is failing is that you have placed the people table on the right side of the join. This means that non matching position records would be discarded. Here is my answer above, rewritten using a right join:
SELECT
po.position_id,
po.position_name,
COALESCE(pe.people_name, 'EMPTY') AS STATUS
FROM people pe
RIGHT JOIN position po
ON po.position_id = pe.people_position_id;
Note carefully that the table order has switched. Most of the time, you will see people using left joins rather than right joins.

PHP mysqli SELECT * from my_table WHERE id = array_of_ids

I have been using this site for years now and this is the first time I'm asking a question here, so kinda scared right now :D
Here's what my problem is, I have got two tables. In table_a I got three columns and in table_b I got 5. So the setup right now looks something like this:
table_a
| r_id | foo | bar |
+------+-------+-----+
| 1 | dude | 5 |
+------+-------+-----+
| 2 | homie | 6 |
+------+-------+-----+
| 3 | bro | 7 |
+------+-------+-----+
table_b
| id | ada | rea | lm | cor |
+----+-------+-----+------+------+
| 5 | ching | ink | jk | 32.4 |
+----+-------+-----+------+------+
| 1 | momo | pal | lmao | 95.5 |
+----+-------+-----+------+------+
| 6 | mama | pen | lol | 26.9 |
+----+-------+-----+------+------+
| 4 | chac | pin | fun | 91.2 |
+----+-------+-----+------+------+
| 7 | chim | lap | funk | 82.4 |
+----+-------+-----+------+------+
| 9 | cho | kil | fin | 38.1 |
+----+-------+-----+------+------+
Now what I'm trying to do is to get all the data from table_a and then only get lm from table_b. I'm getting all the data from table_a like this:
SELECT r_id, foo, bar from table_a
I need to use the ids I get from bar column to get lm from table_b. So is there a way I can pass an array to only get the data based on the ids in an array? If not, then what would be the most efficient way to get those?
The output I'm expecting is jk, lol, funk.
Would appreciate any help, thanks!
You should be looking at using a JOIN to link the two tables together in 1 query...
SELECT r_id, foo, bar, lm
FROM table_a
JOIN table_b on bar = id
try inner join
SELECT a.r_id, a.foo, a.bar, b.lm from table_a as a inner join table_b as b on b.id=a.bar
Why not join?
select group_concat(lm) as lm_list
from table_b b
inner join table_a a on b.id = a.bar
You can use the GROUP_CONCAT() function, with this you would get jk, lol, funk otherwise you would get 3 rows each of one lm value,
For that you can try WHERE IN feature of SQL.
SELECT lm from table_b WHERE id IN(ARRAY_OF_IDS)
Or you can also use join to achieve this
Select tale_a.*, tale_b.lm from tale_a inner join table_b ON tale_a.bar=tale_b.id
I assume that you have array of IDs having IDs.
So first make a comma separated string of that array of IDs like this:
ids_str = implode("," $ARRAY_OF_IDS);
and then use that ids_str in IN os mysql query like below:
SELECT lm from table_b WHERE id IN( ids_str )
You can use INNER JOIN
SELECT tale_a.r_id, tale_a.foo, tale_a.bar ,table_b.lm
FROM tale_a
INNER JOIN table_b
ON tale_a.bar=table_b.id
Note: It returns all columns from table_a and only one column from table_b
Resultant Output:
| r_id | foo | bar | lm |
+------+-------+-----+-----+
| 1 | dude | 5 | jk |
+------+-------+-----+-----+
| 2 | homie | 6 |lol |
+------+-------+-----+-----+
| 3 | bro | 7 |funk |
+------+-------+-----+-----+

Shortening PHP code when comparing multiple MYSQL columns

I use lengths of code similar to this repeatedly in my scripting because I cannot find a shorter way to to compare the MYSQL columns
if ($them['srel1']=="Y" AND $me['Religion']=='Adventist'){$seek11pts=5;}
if ($them['srel2']=="Y" AND $me['Religion']=='Agnostic'){$seek11pts=5;}
if ($them['srel3']=="Y" AND $me['Religion']=='Atheist'){$seek11pts=5;}
if ($them['srel4']=="Y" AND $me['Religion']=='Baptist'){$seek11pts=5;}
if ($them['srel5']=="Y" AND $me['Religion']=='Buddhist'){$seek11pts=5;}
if ($them['srel6']=="Y" AND $me['Religion']=='Caodaism'){$seek11pts=5;}
if ($them['srel7']=="Y" AND $me['Religion']=='Catholic'){$seek11pts=5;}
if ($them['srel8']=="Y" AND $me['Religion']=='Christian'){$seek11pts=5;}
if ($them['srel9']=="Y" AND $me['Religion']=='Hindu'){$seek11pts=5;}
if ($them['srel10']=="Y" AND $me['Religion']=='Iskcon'){$seek11pts=5;}
if ($them['srel11']=="Y" AND $me['Religion']=='Jainism'){$seek11pts=5;}
if ($them['srel12']=="Y" AND $me['Religion']=='Jewish'){$seek11pts=5;}
if ($them['srel13']=="Y" AND $me['Religion']=='Methodist'){$seek11pts=5;}
if ($them['srel14']=="Y" AND $me['Religion']=='Mormon'){$seek11pts=5;}
if ($them['srel15']=="Y" AND $me['Religion']=='Moslem'){$seek11pts=5;}
if ($them['srel16']=="Y" AND $me['Religion']=='Orthodox'){$seek11pts=5;}
if ($them['srel17']=="Y" AND $me['Religion']=='Pentecostal'){$seek11pts=5;}
if ($them['srel18']=="Y" AND $me['Religion']=='Protestant'){$seek11pts=5;}
if ($them['srel19']=="Y" AND $me['Religion']=='Quaker'){$seek11pts=5;}
if ($them['srel20']=="Y" AND $me['Religion']=='Scientology'){$seek11pts=5;}
if ($them['srel21']=="Y" AND $me['Religion']=='Shinto'){$seek11pts=5;}
if ($them['srel22']=="Y" AND $me['Religion']=='Sikhism'){$seek11pts=5;}
if ($them['srel23']=="Y" AND $me['Religion']=='Spiritual'){$seek11pts=5;}
if ($them['srel24']=="Y" AND $me['Religion']=='Taoism'){$seek11pts=5;}
if ($them['srel25']=="Y" AND $me['Religion']=='Wiccan'){$seek11pts=5;}
if ($them['srel26']=="Y" AND $me['Religion']=='Other'){$seek11pts=5;}
EG: if ($them['srel1']=="Y" AND $me['Religion']=='Adventist'){$seek11pts=5;}
I check to seek if the MYSQL column srel1 has a value of Y. if it does then I check to see if the column Religion equals Adventist. If both are true then $seek11pts=5, if they are not both true then nothing happens.
There are 26 srel type columns with either a Y value or null. There are also 26 different values for Religion as you may see. This is but one section of my code. I have multiple HUGE code groupings like this and I'd love to be able to reduce it down to a few lines. I was thinking some kind of array for the religions and another for the numerical endings of the srel columns but I cant get it.
For this current code you can use this:
<?php
$religions = array(1 => 'Adventist','Agnostic','Atheist','Baptist','Buddhist','Caodaism','Catholic','Christian','Hindu','Iskcon','Jainism','Jewish','Methodist','Mormon','Moslem','Orthodox','Pentecostal','Protestant','Quaker','Scientology','Shinto','Sikhism','Spiritual','Taoism','Wiccan','Other');
$count = count($religions) + 1;
for ($i = 1; $i < $count; $i++) {
if ($them["srel$i"]=="Y" && $me['Religion']==$religions[$i]) {
$seek11pts=5;
break;
}
}
While there are ways to accomplish what you ask, you should instead seriously consider restructuring your data.
Better data structure
If your data had a structure more similar to the following:
db.person
+----+------+
| id | name |
+----+------+
| 1 | Nick |
| 2 | Bob |
| 3 | Tony |
+----+------+
PrimaryKey: id
db.religion
+----+---------+
| id | name |
+----+---------+
| 1 | Atheist |
| 2 | Jainism |
| 3 | FSM |
+----+---------+
PrimaryKey: id
db.person_religion
+--------+----------+
| person | religion |
+--------+----------+
| 1 | 2 |
| 2 | 2 |
| 2 | 3 |
| 3 | 1 |
| 3 | 2 |
| 3 | 3 |
+--------+----------+
UniqueIndex: (person,religion)
...everything you're trying to do could be done with simple queries.
SELECT me.id, me.name, meR.name as religion, count(them.id) as matches
FROM person me
LEFT INNER JOIN person_religion meRlookup
ON me.id = meRlookup.person
LEFT INNER JOIN religion meR
ON meRlookup.religion = meR.id
LEFT INNER JOIN person_religion themRlookup
ON meRlookup.religion = themRlookup.religion
LEFT INNER JOIN person them
ON themRlookup.person = them.id
GROUP BY meR.id
I would recommend using laravel or lumen, since these include a "queries generator" that just write a little code (NOTHING SQL) to make queries and that ..

MySQL Multiple Conditions on Group By / Having Clause

I have three tables that are all inter-related with the following structure.
ModuleCategory Table:
+------------------+----------------+------------+
| ModuleCategoryID | ModuleCategory | RequireAll |
+------------------+----------------+------------+
| 90 | Cat A | YES |
| 91 | Cat B | NO |
+------------------+----------------+------------+
ModuleCategorySkill Table:
+------------------+---------+
| ModuleCategoryID | SkillID |
+------------------+---------+
| 90 | 1439 |
| 90 | 3016 |
| 91 | 1440 |
| 91 | 3016 |
+------------------+---------+
EmployeeSkill Table:
+---------+---------+
| EmpName | SkillID |
+---------+---------+
| Emp1 | 1439 |
| Emp1 | 3016 |
| Emp2 | 1440 |
| Emp2 | 3016 |
| Emp3 | 1439 |
| Emp4 | 3016 |
+---------+---------+
Desired Output:
+------------------+-------+
| ModuleCategory | Count |
+------------------+-------+
| Cat A | 1 |
| Cat B | 3 |
+------------------+-------+
I am trying to group by ModuleCategoryID's and get the count of employees which have the skills being tracked.
Normally, I can do the following query to obtain the numbers:
select mc.ModuleCategory, Count(*) as Count from ModuleCategory as mc
join ModuleCategorySkill as mcs on mc.ModuleCategoryID = mcs.ModuleCategoryID join EmployeeSkill as es on es.SkillID= mcs.SkillID
group by mc.ModuleCategoryID
However, I have a column RequireAll in the ModuleCategory table which if it is set to 'YES' should only count employees as 1 only if they have all the skills in the category. If it is set to NO then it can count each row normally and increase the count by the number of rows it groups by.
I can achieve this by writing separate queries for each modulecategoryID and using a having Count() > 1 (which will find me anyone that has all the skills for ModuleCategoryID 90). If there were 3 skills than I would have to change it to Having Count() > 2. If there isn't anyone that has all the skills specified, the count should be 0.
I need a dynamic way of being able to do this since there is a lot of data and writing one query for each ModuleCategoryID isn't the proper approach.
Also, I am using PHP so I can loop through and create a sql string that can help me achieve this. But I know I will run into performance issues on big tables with a lot of skills and modulecategoryID's.
Any guidance on how to achieve this is much appreciated.
You can do it by joining on the total category counts, and then using conditional aggregation:
select modulecategory,
count(case when requireall = 'yes'
then if(s = t, 1, null)
else s
end)
from (
select modulecategory,empname, requireall, count(*) s, min(q.total) t
from employeeskill e
inner join modulecategoryskill mcs
on e.skillid = mcs.skillid
inner join modulecategory mc
on mcs.modulecategoryid = mc.modulecategoryid
inner join (
select modulecategoryid, count(*) total
from modulecategoryskill
group by modulecategoryid
) q
on mc.modulecategoryid = q.modulecategoryid
group by modulecategory, empname
) qq
group by modulecategory;
demo here
This operates under the assumption an employee isn't going to be allocated the same skill twice, if that is something that may happen, this query is alterable to support it, but it seems like a broken scenario to me.
What we have here is an inner query that collates all the information we need (category name, employee name, whether or not all skills are required, how many skills are in the group per employee, and how many there in the group total), with an outer query that uses a conditional count to change how the rows are tallied, based on the value of requireall.

SQL duplicate row

I have a big filter with many options and want to generate the query for sql automaticle and without many code.
GET:
searchvalue=abc
&title=abc
&description=abc
&category=1
&subcategory=2
&zip=7
&city=ke
&country=DE
SQL:
SELECT activity.* FROM activity,subcategory,city,country
WHERE activity.title LIKE '%abc%' OR activity.description LIKE '%abc%'
AND subcategory.SubID = 2
AND city.zip LIKE '%7%'
AND city.City LIKE '%ke%'
AND country.CShort= 'DE'
With this options, I have 1 row in my database.
The answer is this row many times, many many times.
I know that the sql duplicate a row, when a table is not used in a WHERE clausel - but why he do it now and how can I solve that?
Edit: I have a ER, but the database is in german (school project), maybe it help you to understand:
Thanks!
You are doing a cross product by selecting multiple tables. SQL will return every row from the one table combined with every row in the other table.
For example in a database with table a
|------|----------|
| idA | textA |
|------|----------|
| 1 | fooA |
| 2 | barA |
|------|----------|
and table b
|------|----------|
| idB | textB |
|------|----------|
| 1 | fooB |
| 2 | barB |
|------|----------|
when you do
SELECT * FROM a, b
you would get
|------|----------|------|----------|
| idA | textA | idB | textB |
|------|----------|------|----------|
| 1 | fooA | 1 | fooA |
| 1 | fooA | 2 | barA |
| 2 | barA | 1 | fooB |
| 2 | barA | 2 | barB |
|------|----------|------|----------|
To combine these rows logically you do a JOIN. That means you tell in your query which rows belong together. You can do so by JOIN clause or without JOIN clause directly in the WHERE clause.
Back to the example you would do
SELECT * FROM a, b
WHERE a.idA = b.idB
-- or
SELECT * FROM a
JOIN b ON a.idA = b.idB
you would get only 2 rows.
|------|----------|------|----------|
| idA | textA | idB | textB |
|------|----------|------|----------|
| 1 | fooA | 1 | fooA |
| 2 | barA | 2 | barB |
|------|----------|------|----------|
To answer your question:
You have to support JOIN/WHERE clauses to connect your tables activity, subcategory, city and country according to your database schema.
I don't know your table structures but for example clauses like this:
WHERE
...
AND city.country_id = country.id
AND activity.subcategory_id = subcategory.id
AND ...

Categories