SQL Join multiple dismiss same values if one is false - mysql

these are examples my tables:
Employees
id | Name
1 | employee 1
2 | employee 2
3 | employee 3
Busy_Schedule
id | start_date | finish_date | employee_id
1 | 20-11-2017 | 22-11-2017 | 1
2 | 24-11-2017 | 28-11-2017 | 1
3 | 20-11-2017 | 22-11-2017 | 2
4 | 20-11-2017 | 22-11-2017 | 3
I want to choose available employees based on joining these two tables.
For example, I want to know who is available from 21-11-2017 to 23-11-2017.
If I use join, I am getting employee 1 as available because of the multiple entries, whereas he is not available between these two dates.
I am working with Mysql

You need to check if the dates ranges overlaps.
Determine Whether Two Date Ranges Overlap
So when you know what employees are busy on those days, just select the employees NOT IN that group.
SELECT *
FROM Employees
WHERE id NOT IN (SELECT employee_id
FROM Busy_Schedule
WHERE start_date <= '2017-11-23'
AND finish_date >= '2017-11-21')

Related

Different price for additional members of the same group

I have a simple table like this:
group | name | price
1 | john |
2 | mike |
3 | paul |
1 | sean |
4 | jack |
2 | brad |
5 | mick |
1 | bill |
4 | chad |
I have two different price values where 100EUR is for a first member of a group and 50EUR is for all additional members of that same group.
Detailed explanation. If a group has only one member, that member gets a price of 100EUR. If a group has multiple members, the first member gets a price of 100EUR, and all additional members of that same group get a price of 50EUR. There can be unlimited number of groups that will be added additionally.
The result should be like this:
group | name | price
1 | john | 100
2 | mike | 100
3 | paul | 100
1 | sean | 50
4 | jack | 100
2 | brad | 50
5 | mick | 100
1 | bill | 50
4 | chad | 50
I'd need a query which would be able to INSERT/UPDATE all missing price fields whenever I manually run it.
Thank you in advance for looking into that matter.
After a lot of trial and error I found a perfect fully functional solution, based on daviid's clever method. The issue with mysql is that by it's structure won't update tables with select methods as subquery. However, self-join (join or inner join) methods can be used instead in this case. I also had to add auto-incremental id to that table, so the final table structure is:
id | group_id | name | price
1 | 1 | john |
2 | 2 | mike |
3 | 3 | paul |
4 | 1 | sean |
5 | 4 | jack |
6 | 2 | brad |
7 | 5 | mick |
8 | 1 | bill |
9 | 4 | chad |
---
SET SQL_SAFE_UPDATES=0;
UPDATE table_name
SET price = 50;
UPDATE table_name AS a
JOIN
( SELECT id
FROM table_name
GROUP BY group_id
HAVING COUNT(*) >= 1
) AS b
ON a.id = b.id
SET a.price = 100;
Thanks also to Cody and Barmar for usable hints...
A partial answer: you can GROUP BY your "group" field and tack on a HAVING COUNT(group) > 1 to determine if that group has more than 1 member.
That is, to see all groups with more than one member it would look like:
SELECT
group
FROM table
GROUP BY group
HAVING COUNT(group) > 1
That will just tell you which groups have multiple members. Without another way to ensure ordering you cannot tell which member is "first" in their group and thus should be priced at 100 and all others priced at 50.
The following queries are not tested and might contain syntax errors. But they are good enough to understand the principle. There are many possible ways to achieve your result.
Here is my take: I would make use of one query to UPDATE the price on every row and set it to 50 whether it is the first group member or not. >table_name<, of course, needs to be changed to the name of your mentioned table.
UPDATE >table_name<
SET price = 50;
Then I would take care of each individual group and the respective first member by running the following query. Adapt the query to each group by changing the >groupId<.
UPDATE >table_name<
SET price = 100
WHERE id = (
SELECT id
FROM >table_name<
WHERE group = >groupId<
ORDER BY id
LIMIT 1
);
Take a look a the nested query: It queries the table for all members of only one group, orders them in ascending order and only returns an id per member. By applying LIMIT to the query, the result will just be the first group member's id. The resulting id can then be used in the other query to update the price and set it to 100.
But be careful: If you insert/delete (new) members with an id that is not just counting up, this query might select a "new first member".

Write query on sql

I have one monitoring table with client ID columns ID, last login date to application Time. I wrote a query to display the table at what time the clients had access to the system in the form: Time - Number of entries at this time - Client IDs.
Request:
select Time, count (*) as Quantity, group_concat (ClientID) from monitoring group by Time;
How do I write the following query? Display the table in the same form, only now it is necessary for each time when at least 1 client had access, display the id of all clients who did not have access at that time.
UPD.
+---------------------+-------------+----------------+
| Time | Quantity | ClientID |
+---------------------+-------------+----------------+
| 2018-06-14 15:51:03 | 3 | 311,240,528 |
| 2018-06-14 15:51:20 | 3 | 314,312,519 |
| 2019-01-14 06:00:07 | 1 | 359 |
| 2019-08-21 14:30:04 | 1 | 269 |
+---------------------+-------------+----------------+
These are the IDs of clients who currently had access. And you need to display the IDs of all clients who did not have access at that particular time
That is, in this case:
+---------------------+-------------+-----------------------------+
| Time | Quantity | ClientID |
+---------------------+-------------+-----------------------------+
| 2018-06-14 15:51:03 | 5 | 269,359,314,312,519 |
| 2018-06-14 15:51:20 | 5 | 311,240,528,359,269 |
| 2019-01-14 06:00:07 | 7 | 311,240,528,314,312,519,269 |
| 2019-08-21 14:30:04 | 7 | 311,240,528,314,312,519,359 |
+---------------------+-------------+-----------------------------+
It is advisable not to take into account the day and time, but only the year and month. But as soon as it comes out. Thanks.
You can generate all possible combinations of clients and time with a cross join of two select distinct subqueries, and then filter out those that exist in the table with not exists. The final step is aggregation:
select t.time, count(*) as quantity, group_concat(c.clientid) as clientids
from (select distinct time from monitoring) t
cross join (select distinct clientid from monitoring) c
where not exists (
select 1
from monitoring m
where m.time = t.time and m.clientid = c.clientid
)
group by t.time
It is unclear to me what you mean by the last sentence in the question. The above query would generate the results that you showed for your sample data.

How can i display records from one table where the number of outputed records depend on another table

Vehicle
+--------+--------+-----------+
| regNo | make | model |
+------- +--------+-----------+
| SM56ED | BMW | 3 Series |
+--------+--------+-----------+
| GH45EM | Audi | A3 |
+--------+--------+-----------+
| LM33ZG | Toyota | Yaris |
+--------+--------+-----------+
| ZR88HH | Suzuki | Swift |
+--------+--------+-----------+
Booking
+----+---------+------------+------------+
| id | regNo | date_from | date_to |
+----+---------+------------+------------+
| 1 | SM56ED | 2015-03-20 | 2015-04-10 |
+----+---------+------------+------------+
| 2 | LM33ZG | 2015-05-15 | 2015-05-22 |
+----+---------+------------+------------+
So lets say i have these two tables. I want to check against two other dates, lets say:
from: '2015-03-25'
to: '2015-04-05'
I want to display every car make, model which doesn't have a booking or the booking doesn't fall between the specified dates. So with the example above it should display the Audi, Toyota and Suzuki but not the BMW since there's a booking between the dates specified for that vehicle.
I have tried to use 'WHERE NOT EXISTS', inside checking if passed in dates fall 'BETWEEN' 'date_from' and 'date_to'. However this would either return all the vehicles if no vehicle is booked, or return 0 vehicles if at least one vehicle is booked between the dates.
Any advice is appreciated, thank you.
You have to relate the query in the not exists part to the outer query (eg. make a correlated query):
select * from Vehicle v
where not exists (
select 1 from Booking
where regNo = v.regNo
and date_from <= '2015-04-05'
and date_to >= '2015-03-25'
)
A query built on the exists predicate is often the fastest solution.
I don't have a db to test this out on ATM, but how about a join like so:
select * from Vehicle v left join Booking b on v.regNo = b.regNo where b.id is null or (b.date_from > '2015-03-25' and b.date_to < '2015-04-05')

Update table A based on count in table B

I have 2 tables (SALESMAN, SOLD), where the SALES table records what cars were sold each day. At night a job runs that must increase the SOLD count in the SALESMAN table. For example, here are two tables:
SALESMAN SALES
+-------------+-----------+------+ +------------+---------+
| SALESMANID | NAME | SOLD | | SALESMANID | VEHICLE |
| 1 | Bob | 1 | | 1 | GM |
| 2 | Charlie | 7 | | 1 | Chrys |
| 3 | Dave | 0 | | 1 | GM |
+-------------+-----------+------+ | 3 | Dodge |
| 3 | GM |
| 2 | Hummer |
+------------+---------+
After the UPDATE has run, Bob's sold count will increase to 4, Charlie's sold count will increase to 8, and Dave's sold count will increase to 2. I'm trying to create something like:
UPDATE SALESMAN SET SOLD=SOLD+(
SELECT COUNT(*)
FROM SALES
WHERE SALESMAN.SALESMANID = SALES.SALESMANID
)
Is this the right way to solve the problem?
I found a similar question here: (Updating one SQL table based on data in another table) but it's not clear if it will selectively updates table A in their example, or all records in table A.
UPDATE: I fixed the typo above but it still doesn't work. 0 rows affected when I run the query.
yes its right your query just change this
WHERE SALESAN.SALESMANID
to
WHERE SALESMAN.SALESMANID
your demo
i dont know why you didnt try it your self before asking a question.
INSERT INTO SALESMAN (SALESMANID, SOLD) (SELECT SALEMANID, COUNT(*) as c FROM SOLD GROUP BY SALEMANID) ON DUPLICATE KEY UPDATE SOLD = c
You may need to name the select and use .c
If the sales table is deleted after this nightly process runs, then this should work
Update m Set
Sold = sold +
(Select Count(*) From Sales
Where SalesmanId = m.SalesmanId)
From Salesman m
UPDATE SALESMAN a,
(SELECT SALESMANID, COUNT(*) SALE_COUNT
FROM SALES
group by SALESMANID) b
set a.SOLD=a.SOLD+ b.SALE_COUNT
WHERE a.SALESMANID = b.SALESMANID;
see SQL Fiddle

constructing a query for the following table

can anyone generate a query for me.
Lets say i have a table sales(saleID, date_of_sales, customerID, itemID, saleprice)
date_of_sales is the datetime field which stores the time of the sale.
customerID is self exlpaining tells to whom item was sold.
itemID is ID of the item sold.
saleprice is the price that the item was sold.
I want to construct a query which will give out the detail of the last purchase by each customers. this could be done by using date_of_sales.
Example table
saleID | date_of_sales | customerID | itemID | saleprice
101 | 2008-01-01 | C2000 | I200 | 650 |
102 | 2010-01-01 | C2000 | I333 | 200 |
103 | 2007-01-01 | C3333 | I111 | 800 |
104 | 2009-12-12 | C3333 | I222 | 100 |
this is the example data table, there are only two customer for simplicity.
customer C2000 did his last purchase
on 2010-01-01
customer C3333 did his last purchase
on 2009-12-12
I want to get a result like this
customerID | date_of_sales | itemID | saleprice
C2000 | 2010-01-01 | I333 | 200 |
C3333 | 2009-12-12 | I222 | 100 |
This might be what you are looking for...
SELECT *
FROM sales
WHERE sales.date_of_sales = (SELECT MAX(date_of_sales)
FROM sales s2
WHERE s2.customerID = sales.customerID);
There is a slight problem with it; if there were two sales on the same day to the same customer, you'll get two rows (unless your date-of-sales column includes the time as well). I think the same applies to the answer above, though.
Additionally, if you DO want to get results based on only a SINGLE entry of the maximum date, I would use the query by #Sachin Shanbhag above, but add a maximum sales ID value too... Since that would be implied as sequential, whichever was entered last would probably be the most recent.
SELECT S.* FROM
sales S
INNER JOIN
( SELECT
customerID,
MAX(date_of_sales) dos,
MAX(SalesID) maxSale
FROM
sales
GROUP BY customerID
) S2 ON S.customerID = S2.customerID
AND S.date_of_sales = S2.dos
AND S.SalesID = S2.maxSale