Update particular value in table column mysql - mysql

I have table like this:
id business_id path photo
1 11 1.jpg 0
2 11 2.jpg 0
3 15 1.jpg 0
4 15 3.jpg 0
5 15 4.jpg 0
6 21 scan1.jpg 0
7 21 scan2.jpg 0
8 22 1.jpg 1
....
I want to update table so that for each business lets say in above scenario for business 11. one of the path should have photo set to 1.
If photo is already set to 1 (like for business_id = 22) above it should not change that.
I think below query will work for 1 business_id at a time:
Update business
set photo = 1
where id = 11 limit 1
But my question is how can I run this in a batch? So I can update all at once.

You can update your table by using below query,It will get the maximum for each business_id which has all photos set to 0 and using join you sub select will update a single record per business_id to photo = 1
update business b
join (select max(id) id, business_id
from business
group by business_id
having sum(photo = 0) = count(*)) t
on(b.id = t.id)
set b.photo = 1
DEMO

You could try this query:
UPDATE business SET photo = 1 WHERE id IN
(SELECT MIN(id) , MAX(photo) FROM business
GROUP BY business_id HAVING max(photo) = 0)
Additional info: The next query gives you a list of rows where business doesn't have any photo. This query was the initial point for my answer.
SELECT business_id , MAX(photo) FROM business
GROUP BY business_id HAVING max(photo) = 0

Related

How to select a row from table1 if the row id isn't present in table2 more than x times

accounts as a1 | team_logs as tl1
--------------------------------------------------------
id Name counter | id team_id user_id account_id
1 Account 1 2 | 1 1 100 1
2 Account 2 2 | 2 2 200 1
3 Account 3 0 | 3 3 300 2
... | 4 2 200 2
This is an account review app. Based on the 2 tables above a query is needed that will output 1 account from a1 table based on the tl1 records as below:
A team member is requesting an account, and once an account is assigned to him a log entry is made in tl1 that an account_id is assigned to him.
An account can be assigned to a Team only once.
An account can be assigned to x teams (In the above example we have only 3 teams).
An record can be reviewed x times(In the example above it can be reviewed 3 times).
I had a project where I had only 3 teams and each teams logs were stored in its own table, and I had this query which worked:
Example for Team1
SELECT `a1`.*
FROM `accounts` AS `a1`
LEFT JOIN `team1_logs` AS `tl1` ON tl1.account_id = a1.id
WHERE (tl1.account_id IS NULL)
AND (a1.counter < '3')
ORDER BY RAND()
LIMIT 1
a1 has a counter column which has a value that represents the number of times a row was shown to teams. Now my project can house x teams, we made the teams dynamic, so making a table log for each team isn't an option.
So in the above tables if i want an account to be reviewed(assigned to a team member) 3 times.
Account 1 can be reviewed 1 more time by any team that isn't 1 and 2
Account 2 can be reviewed 1 more time by any team that isn't 2 and 3
What would my new query need to look like if i want to get the next first available record, based on the 1-4 criteria from above?
The data in Table 2 is more than enough, you don't need to know any other
data to make the needed query.
team_id is an query input (since we need to output an account to the team
member)
Answer
Assuming that I am a team member of team 1
SELECT DISTINCT a.*
FROM accounts AS a
LEFT JOIN (
SELECT account_id, team_id FROM team_logs) AS tl1 ON a.id = tl1.account_id
WHERE a.id NOT IN (
SELECT account_id FROM team_logs WHERE team_id =1)
AND a.counter < 3
ORDER BY a.id ASC
If you just want to see which teams are not allowed to review the account again, join with a subquery that uses GROUP_CONCAT to get the list of teams that have reviewed it.
SELECT a.*, 3 - counter AS remaining_reviews, IFNULL(tl.already_reviewed, '') AS already_reviewed
FROM accounts AS a
LEFT JOIN (
SELECT account_id, GROUP_CONCAT(team_id ORDER BY team_id) AS already_reviewed
FROM team_logs
GROUP BY account_id) AS tl ON a.id = tl.account_id
WHERE a.counter < 3
DEMO

Sql select where a column has been set atleast once

I have this table
**applications**
id user_id company_id shortlisted
1 10 99 0
2 10 100 1
3 10 101 1
4 10 102 0
5 11 99 1
6 12 99 0
6 12 101 0
What I want is to select all users
which have been shortlisted at-least once
which have not been shortlisted at all
For the first case, i have the following query:
SELECT user_id
from applications
where shortlisted=1
Group
By user_id
and this gives me the expected result like below
**applications**
user_id
10
11
But I'm trying the following query for the second case and it returns me an empty set:
Select user_id
from applications as Application
where shortlisted=0
and NOT EXISTS(Select user_id from applications where user_id=Application.user_id and shortlisted=1)
What am i missing?
PS: Please ignore any typos as i typed them manually for this post.
To get both results in a single query simply use aggregation:
select user_id, max(shortlisted) as was_shortlisted
from applications
group By user_id
You can use group by and having for both.
For the first:
select user_id
from applications
group By user_id
having max(shortlisted) = 1;
For the second:
select user_id
from applications
group By user_id
having max(shortlisted) = 0;
In all honesty, your version with the where is more efficient for the first query. This is just to show how closely related the queries are.
You can try following query;
select user_id from table1
group by user_id having MIN(shortlisted) = 1
This will give you to at least have shortlisted = 1 condition and don't have shortlisted = 0 records.

mysql select default values from table if user specific ones aren't found

I've got a table of statuses.
ID UserID StatusID Description
1 0 0 ready
2 0 1 on hold
3 0 2 cancelled
4 3 1 waiting
5 3 2 deleted
6 3 4 waiting on supplier
7 4 5 postponed
etc...
UserID 0 holds my default descriptions. I want to pull out all the status text for a user and the defaults if there are no user values with the same status ID.
eg user ID 3 should return
ID UserID StatusID Description
1 0 0 ready
4 3 1 waiting
5 3 2 deleted
6 3 4 waiting on supplier
eg user ID 4 should return
ID UserID StatusID Description
1 0 0 ready
2 0 1 on hold
3 0 2 cancelled
7 4 5 postponed
User ID 7 should return
ID UserID StatusID Description
1 0 0 ready
2 0 1 on hold
3 0 2 cancelled
so far I have this:
select description.* from status_description description
join (
select max(id) as maxid from (
select * from status_description default where default.user_id = 0
union
select * from status_description userstatus where ectfsa.user_id = 67
) as subset
group by subset.ID
) as newest_desc on newest_desc.maxid = description.id
order by StatusID asc;
Where I union both the users statuses and the default statuses and then join the max ID per statusID back with the original table to get the user and defaults.
This works fine until someone adds a new USERID0 status with a higher ID. Eg we decide that all users should now have an option of "postponed" and we add a line
ID UserID StatusID Description
8 0 5 next week
which should be the same "status" as "postponed" but worded differently for all users to what UserID 4 has.
If there a more graceful way of doing this without using Max and just selecting defaults and adding user statuses overwriting defaults where they already exist?
I need to keep this within mysql (ie not php) as its going to be a join to another query to pull out user specific descriptions for another report.
I think this may be a solution :
select * from (
select StatusID,Description from status_description default where default.user_id = 0
union
select StatusID,Description from status_description userstatus where ectfsa.user_id = 67
) as StatusID;
I don't need the UserID in the result or the ID. By removing these from the union by replacing the * with field names the union automatically removes duplicates, or at least appears to...

mySQL view to show distict value and all pertaining rows beneath it

I am using mySQL. I have a table that is updated everyday based on our sku. The sku has duplicate values because there is a pricing tier associated with it. I need to create a view that will show all the rows but only 1 sku and the associated sku rows beneath it so i can export everyday for an update in magento. Magento does not allow duplicate sku's during an import. Here is an example:
sku _tier_price_qty _tier_price_price
013964223286 10 1
50 1
100 1
9332153001025 5 1
25 1
50 1
9332153001032 5 1
25 1
50 1
9332153001063 5 1
25 1
50 1
9332153001049 5 1
25 1
50 1
640420002569 5 1
25 1
50 1
640420002538 5 1
25 1
50 1
640420002521 5 1
25 1
50 1
Although this type of formatting might be better to handle in a reporting application this query should do what you want:
select
case when x.tier_qty is not null then t.sku else null end tier_qty,
t.tier_qty,
t.tier_price
from t
left join (
select sku, min(tier_qty) tier_qty
from t
group by sku
) x on t.sku = x.sku and t.tier_qty = x.tier_qty
order by t.sku, t.tier_qty;
http://www.sqlfiddle.com/#!9/3314bd/1
Can you try this?
select case when (select MIN(tier_qty) from products where sku = o.sku) = tier_qty
then sku
else null,
tier_qty,
tier_price
from products o
order by sku, tier_qty

Mysql JOIN with extra priority column

I have two days trying to do this query with no luck.
I have two tables 'DEMAND' and 'DEMAND_STATE' (one to many relation). The table DEMAND_STATE have millions entries.
CREATE TABLE DEMAND
(
ID INT NOT NULL,
DESTINY_ID INT NOT NULL
)
CREATE TABLE DEMAND_STATE
(
ID INT NOT NULL,
PRIORITY INT NOT NULL,
QUANTITY DOUBLE NOT NULL,
CASE_ID INT NOT NULL,
DEMAND_ID INT NOT NULL,
PHASE_ID INT NOT NULL
)
The QUANTITY of the DEMAND_STATE is given according to a CASE_ID and PHASE_ID. We have 'N' PHASES in 'M' CASES. Always the same number of Phases in all Cases. We always have a initial Base Quantity called 'BASE CASE' in the Case with CASE_ID = 1.
For example to obtain quantity for Case (id=2) and Case Base (id=1)
select D.*, S.PRIORITY, S.QUANTITY, S.CASE_ID, S.DEMAND_ID, S.PHASE_ID
FROM DEMAND D
join DEMAND_STATE S on (D.ID = S.DEMAND_ID)
WHERE (S.CASE_ID = 2 OR S.CASE_ID = 1)
(paste only for id=8)
ID PRIORITY QUANTITY CASE_ID DEMAND_ID PHASE_ID
8 0 85 1 8 1
8 0 83 1 8 2
8 0 88 1 8 3
8 0 89 1 8 4
8 10 85 2 8 1
8 10 84 2 8 2
8 10 86 2 8 3
8 10 89 2 8 4
We need to obtain for all Demand in 'DEMAND' only the Quantity for Each Phase with MAX priority. The idea is no duplicate DEMAND_STATE data for each new Case creation. Only create new state rows when Demand-Case-Phase is different to Case Base. This is a new project and we accept changes in model for better performance.
I also tried with the MAX calculation. This query over DEMAND_STATE works fine but only obtain data for a concrete DEMAND_ID. Further i think this solution can be so expensive.
SELECT P.ID, P.QUANTITY, P.CASE_ID, P.DEMAND_ID, P.PHASE_ID
FROM DEMAND_STATE P
JOIN (
SELECT PHASE_ID, MAX(PRIORITY) max_priority, S.DEMAND_ID
from DEMAND_STATE S
WHERE S.DEMAND_ID = 1
AND (S.CASE_ID=1 OR S.CASE_ID=2)
GROUP BY S.PHASE_ID
) SUB
ON (SUB.PHASE_ID = P.PHASE_ID AND SUB.max_priority = P.PRIORITY)
WHERE P.DEMAND_ID = 1
GROUP BY P.PHASE_ID
The result:
ID QUANTITY CASE_ID DEMAND_ID PHASE_ID
1 86 1 1 1
2 85 1 1 2
3 81 1 1 3
8 500 2 1 4
This is the result expected:
ID ID PRIORITY QUANTITY CASE_ID PHASE_ID
8 1 0 86 1 1 (data from Case Base id=1 priority 0)
8 2 10 85 1 2 (data from Case Baseid=1 priority 0)
8 3 10 81 1 3 (data from Case Base id=1 priority 0)
8 64 10 500 2 4 (data from Case id=2 priority 10)
thank for help :)
Edit:
Result of Simon proposal:
ID QUANTITY CASE_ID DEMAND_ID PHASE_ID
1 86 1 1 1
2 85 1 1 2
3 81 1 1 3
4 84 1 1 4 (this row shouldnt exist)
8 500 2 1 4 (this is the correct row)
Also would have to join it with DEMAND
#didierc response:
ID ID MAX(S.PRIORITY) QUANTITY CASE_ID PHASE_ID
1 8 10 500 2 4
2 13 10 81 2 1
2 14 10 83 2 2
2 15 10 84 2 3
3 21 10 81 2 1
4 31 10 86 2 3
4 32 10 80 2 4
4 29 10 85 2 1
4 30 10 81 2 2
we need for each DEMAND four rows with the quantity Value. In Case Base we have four quantity and in Case 2 we only change the quantity for phase 4. We need always four rows for each demand.
Database DEMAND_STATE data:
ID PRIORITY QUANTITY CASE_ID DEMAND_ID PHASE_ID
1 0 86 1 1 1
2 0 85 1 1 2
3 0 81 1 1 3
4 0 84 1 1 4
8 10 500 2 1 4
We need to obtain for all Demand in 'DEMAND' only the Quantity for Each Phase with MAX priority
I translate the above, according to your sample result set, as:
SELECT
D.ID, S.ID, MAX(S.PRIORITY), S.QUANTITY, S.CASE_ID, S.PHASE_ID
FROM DEMAND D
LEFT JOIN DEMAND_STATE S
ON D.ID = S.DEMAND_ID
GROUP BY S.PHASE_ID, S.DEMAND_ID
Update:
To get the maximum priority for each pair(demand_id,phase_id)n we use the following query:
SELECT
DEMAND_ID, PHASE_ID, MAX(PRIORITY) AS PRIORITY
FROM DEMAND_STATE
GROUP BY DEMAND_ID, PHASE_ID
Next, to retrieve the set of phases for a given demand, just make an inner join on demand state:
SELECT S.* FROM DEMAND_STATE S
INNER JOIN (
SELECT
DEMAND_ID, PHASE_ID, MAX(PRIORITY) AS PRIORITY
FROM DEMAND_STATE
GROUP BY DEMAND_ID, PHASE_ID
) S2
USING (DEMAND_ID,PHASE_ID, PRIORITY)
WHERE DEMAND_ID = 1
If you want to limit the possible cases, include a where clause in the query S2:
SELECT S.* FROM DEMAND_STATE S
INNER JOIN (
SELECT
DEMAND_ID, PHASE_ID, MAX(PRIORITY) AS PRIORITY
FROM DEMAND_STATE
WHERE CASE_ID IN (1,2)
GROUP BY DEMAND_ID, PHASE_ID
) S2
USING (DEMAND_ID,PHASE_ID, PRIORITY)
WHERE DEMAND_ID = 1
However, your comments and update indicates that MAX(PRIORITY) does not seem very relevant after all. My understanding is that you have a base case, which may be overriden by another case in a given scenario (that scenario is the pair base case + some other case). Clarify that point in your question body if this is incorrect. If that is the case, you may change the above query by replacing PRIORITY by CASE_ID:
SELECT S.* FROM DEMAND_STATE S
INNER JOIN (
SELECT
DEMAND_ID, PHASE_ID, MAX(CASE_ID) AS CASE_ID
FROM DEMAND_STATE
WHERE CASE_ID IN (1,2)
GROUP BY DEMAND_ID, PHASE_ID
) S2
USING (DEMAND_ID,PHASE_ID, CASE_ID)
WHERE DEMAND_ID = 1
The only reason I see from having a priority is if you wish to combine more than 2 cases, and use priority to select which case will prevail depending on the phase.
You may of course prepend an inner join on DEMAND to include the related demand data.
Use of subqueries should be able to do as you wish, if I understand your question correctly. Something along the lines of the following:
SELECT
P.ID,
P.QUANTITY,
P.CASE_ID,
P.DEMAND_ID,
P.PHASE_ID
FROM DEMAND_STATE P
INNER JOIN (
-- Next level up groups it down and so gets the rows first returned for each PHASE_ID, which is the highest priority due to the subquery
SELECT
D.PHASE_ID,
D.PRIORITY,
D.DEMAND_ID
FROM (
-- Top level query to get all rows and order them in desc priority order
SELECT
S.PHASE_ID,
S.PRIORITY,
S.DEMAND_ID
FROM DEMAND_STATE S
WHERE S.DEMAND_ID IN (1) -- Update this to be whichever DEMAND_IDs you are interested in
AND S.CASE_ID IN (1,2)
ORDER BY
S.PHASE_ID ASC,
S.DEMAND_ID ASC,
S.PRIORITY DESC
) D
GROUP BY
D.PHASE_ID,
S.DEMAND_ID
) SUB
ON SUB.PHASE_ID = P.PHASE_ID
AND SUB.DEMAND_ID = P.DEMAND_ID
The top level subquery exists to get the rows you are interested in and order them in an order which allows predictable results when they are then grouped down by PHASE_ID and DEMAND_ID. This in turn allows a simple INNER JOIN to DEMAND_STATE hopefully (unless I have misunderstood your query)
This may still be expensive though depending on how much data is within that top level query.