Update table A based on count in table B - mysql

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

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".

SQL Join multiple dismiss same values if one is false

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')

MYSQL SELECT trouble (AND operator on on column)

I have a table similar to the following:
+----+------+----------+
| id | Order| SalesMan |
+----+------+----------+
| 1 | 1001 | 1 |
| 2 | 1001 | 2 |
| 3 | 1002 | 1 |
| 4 | 1002 | 4 |
| 5 | 1003 | 2 |
+----+------+----------+
I want to select the the orders sharing multiple Sales Men with an AND operator. Like showing only orders made by Salesmen 1 & 2.
A/c to what i understand about your question, there will be one order with multiple entries of salesman associated. If you just have to know about those orders which salesman 1 and 2 both are associated with then,you can do something like this:
SELECT `order`
FROM tbl
WHERE salesMan=1
AND `order`
IN (select `order` from tbl where salesMan=2)
Here's a SQL Fiddle for better understanding..
EDIT: I have changed the query a/c to your need:
SELECT orders
FROM tbl
WHERE salesMan
IN (1,2,3)
GROUP BY orders
HAVING count(orders)>1;
check the fiddle demo here
Use GROUP BY and HAVING Clause.
Query
SELECT salesMan
FROM tbl
GROUP BY salesMan
HAVING COUNT(salesMan) > 1;
Fiddle Demo
Try this
SELECT * FROM table WHERE SalesMan IN(1,2);

MySQL Query to retrieve maximum value among certain criteria

I have products with different rankings. The products may be members of a supergroup (like Cream).
product_id | supergroup | rank | other_info
1 | Cream | 3 | Eric
2 | Zep | 1 | Jimmy
3 | Zep | 4 | Jon Paul
4 | Cream | 3 | Jack
5 | Cream | 4 | Ginger
6 | Who | 4 | Roger
7 | Who | 5 | John
8 | Who | 3 | Pete
I want to get the max product rank from each group, along with other info for that product id. Ranks are not meant for intragroup ranks. They are ranks that work across all products in the system. So more than one product may have the same rank, even in the same group.
EDIT: fixed "other_info". I had some gibberish there. Also added a row. Results should be from highest rank to lowest. But they also should only include the highest ranking product_id from each supergroup, along with matching other_info.
product_id | supergroup | rank | other_info
2 | Zep | 1 | Jimmy
8 | Who | 3 | Pete
1 | Cream | 3 | Eric
Can I do that with a simple query? The existing system's query already involves a GROUP BY statement on the supergroup, and no aggregators in the SELECT. That results in a random, but coherent row from within the group. What is the simplest way to modify the query to get a complete row, but always of the highest-ranked member of each super group.
If there is no way, what about this: Is this possible without GROUP BY?
SELECT t.*
FROM your_table t
JOIN (
SELECT MIN(product_id) as product_id #if there are multiple products with the same (min) rank in the same supergroup - get the one with lowest product_id
FROM your_table tt
JOIN (
SELECT supergroup, MIN(rank) as min_rank
FROM your_table
GROUP BY supergroup
) mr ON mr.supergroup = tt.supergroup AND mr.min_rank = tt.rank
GROUP BY tt.supergroup, tt.rank
) as mid ON mid.id.product_id = t.product_id
ORDER BY whatever_you_need_to
You need an index on (supergroup,rank) for this to run efficiently.

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