Update a column with count of the values from another column - mysql

I am creating a MySQL table with the following query.
CREATE TABLE log_table (id INTEGER, street TEXT, status INTEGER)
and filling it with the following query:
INSERT INTO log_table (`id`, `street`, `status`) VALUES
('1', 'main_street', '0'),
('2', '1st_street', '0'),
('3', '1st_street', '0'),
('4', 'main_street', '0'),
('5', '2nd_street', '0'),
('6', '1st_street', '0'),
('7', 'main_street', '0'),
('8', '2nd_street', '0');
I am trying to update the status column with the count of the street column.
For example for the first row status column should be 3 because main_street appears 3 times in street column.
I have tried the following query but it doesn't work.
UPDATE log_table l1 SET status =
(SELECT COUNT(*) FROM log_table l2 WHERE l2.street = l1.street);
It gives an error that says "You can't specify target table 'l1' for update in FROM clause". What could be the issue?

You can use a join:
UPDATE log_table l1
join (SELECT COUNT(*) as n, street FROM log_table l2 group by l2.street) as l3 on l1.street=l3.street
SET status = l3.n
SQLFiddle

Related

Query for any person has any account of type x

Imagine I have two tables, Person and Account, a person can have accounts (type 1 and/or 2).
I'd like to get a list of people who have at least one type 1 account, and also get a list of people who don't have a type 1 account. I'm using Query #1 and #2 for this respectively but I think I'm doing something is wrong because the results do not match.
Schema (MySQL v5.7)
CREATE TABLE Person (
`PersonId` INTEGER,
`Name` VARCHAR(5)
);
INSERT INTO Person
(`PersonId`, `Name`)
VALUES
('1', 'Leo'),
('2', 'Natan'),
('3', 'Vera'),
('4', 'Julio'),
('5', 'Mary');
CREATE TABLE Accounts (
`AccountId` INTEGER,
`PersonId` INTEGER,
`Type` INTEGER
);
INSERT INTO Accounts
(`AccountId`, `PersonId`, `Type`)
VALUES
('1', '1', '0'),
('2', '1', '1'),
('3', '2', '0'),
('4', '2', '0'),
('5', '3', '1'),
('6', '4', '0'),
('7', '1', '0'),
('8', '2', '0');
Query #1
SELECT * FROM Person AS PD
LEFT JOIN Accounts AS AC ON AC.PersonId = PD.PersonId
WHERE AC.Type = 1;
PersonId
Name
AccountId
PersonId
Type
1
Leo
2
1
1
3
Vera
5
3
1
Query #2
SELECT * FROM Person AS PD
LEFT JOIN Accounts AS AC ON AC.PersonId = PD.PersonId
WHERE AC.Type = 0;
PersonId
Name
AccountId
PersonId
Type
1
Leo
1
1
0
1
Leo
7
1
0
2
Natan
3
2
0
2
Natan
4
2
0
2
Natan
8
2
0
4
Julio
6
4
0
View on DB Fiddle
EXISTS and NOT EXISTS are the more suitable solutions for this requirement:
-- Account type = 1
SELECT p.* FROM Person AS p
WHERE EXISTS (
SELECT *
FROM Accounts AS a
WHERE a.PersonId = p.PersonId AND a.Type = 1
);
-- No type 1 account
SELECT p.* FROM Person AS p
WHERE NOT EXISTS (
SELECT *
FROM Accounts AS a
WHERE a.PersonId = p.PersonId AND a.Type = 1
);
See the demo.

MySQL-Count consective number

Write a SQL query to find number position as well number and consective number count
CREATE TABLE Logs (
`Id` INTEGER,
`Num` INTEGER
);
INSERT INTO Logs
(`Id`, `Num`)
VALUES
('1', '1'),
('2', '1'),
('3', '1'),
('4', '2'),
('5', '1'),
('6', '2'),
('7', '2');
Prefere Return
StartId Num Count
1 1 3
4 2 1
5 1 1
6 2 2
and also can i get any suggestion which function can be use with case function in MySQL Function
Looking at your data and expected results, I believe your expectations are inconsistent, eg you can either have 1 and 6 or 3 and 7.
What you need to do is group the data by successive num values and aggregate the results.
with gp as (
select *,
Row_Number() over(order by id)
- Row_Number() over(partition by num order by id) g
from logs
)
select Min(id) Id,
num, Count(*) Count
from gp
group by g, num
order by id

case when wont work with update statement

For my MySQL query,
update Products
set new_price = (
case when change_date>'2019-08-16' then new_price=100 else new_price end
)
;
the update statement sets the new price to 0. why?
table details:
insert into Products (product_id, new_price, change_date) values ('1', '20', '2019-08-14');
insert into Products (product_id, new_price, change_date) values ('2', '50', '2019-08-14');
insert into Products (product_id, new_price, change_date) values ('1', '30', '2019-08-15');
insert into Products (product_id, new_price, change_date) values ('1', '35', '2019-08-16');
insert into Products (product_id, new_price, change_date) values ('2', '65', '2019-08-17');
insert into Products (product_id, new_price, change_date) values ('3', '20', '2019-08-18');
select * from Products;
You are attempting to set new_price to the result of the boolean expression new_price=100, which will be 0 unless new_price already has the value 100. Just remove the new_price= and the code will work fine:
update Products
set new_price = case when change_date>'2019-08-16' then 100
else new_price
end
Demo on dbfiddle
It sets the value to zero because new_price = 100 is a boolean expression -- and that evaluates to either 0 or 1.
If this is all you are doing, you should filter in the where clause:
update Products
set new_price = 100
where change_date > '2019-08-16';

Order of SQL Query Clauses

I ran into a situation where I don't seem to get what SQL is doing. I have the following table and want to give out all the sorts of coffee which have the most amount of rating=5 with the amount itself.
create table likes
(
CName varchar(30),
UName varchar(30),
Rating int
);
insert into likes (CName, UName, Rating)
values ('Java', 'Klaus', '5'),
('Super', 'Klaus', '5'),
('MP', 'Klaus', '3'),
('Java', 'Marc', '5'),
('Mp', 'Marc', '5'),
('Super', 'Marc', '2'),
('Java', 'Nine', '2'),
('Super', 'Nine', '0'),
('MP', 'Karo', '3'),
('Super', 'Fabian', '4');
However this solution doesn't work as intended
SELECT
favcof.CName, favcof.cnt
FROM
(SELECT l.CName, COUNT(CName) cnt
FROM likes l
WHERE l.rating = 5
GROUP BY CName) favcof
WHERE
favcof.cnt = (SELECT MAX(favcof.cnt))
It executes as if there is no outer where-clause and gives out all sorts of coffees with their amount of rating = 5.
The expression (select max(favcof.cnt)) doesn't do anything. You can just drop the select and you will get favcof.cnt = favcof.cnt.
This is a little complicated, because favcof.cnt = max(favcof.cnt) would generate a syntax error because aggregation functions are not allowed in the where clause. So, the select subquery is actually an aggregation subquery with no from. Because there is only one value, it returns that value.
You want a correlated subquery. This would look like:
SELECT favcof.CName, favcof.cnt
FROM (SELECT l.UName, count(UName) as cnt
FROM likes l
WHERE l.rating=5
GROUP BY UName
) favcof
WHERE favcof.cnt = (SELECT MAX(favcof2.cnt)
FROM (SELECT l2.UName, count(l2.UName) as cnt
FROM likes l2
WHERE l2.rating=5
GROUP BY l2.UName
) favcof2
);
There are definitely other ways to write this query. However, this should help you understand why your version does not do what you want it to do.
you can do like this
DECLARE #likes AS TABLE(CName NVARCHAR(50), UName NVARCHAR(50), Rating INT)
insert into #likes (CName, UName, Rating) values
('Java', 'Klaus', '5'),
('Super', 'Klaus', '5'),
('MP', 'Klaus', '3'),
('Java', 'Marc', '5'),
('Mp', 'Marc', '5'),
('Super', 'Marc', '2'),
('Java', 'Nine', '2'),
('Super', 'Nine', '0'),
('MP', 'Karo', '3'),
('Super', 'Fabian', '4');
SELECT UName, COUNT(CName) Cnt FROM #Likes
WHERE Rating = (SELECT MAX(Rating) FROM #Likes)
GROUP BY UNAME
DEMO

SQL Query to select records based on 2 different values in the same field and a condition

I Created a table like this for indian railways project:
CREATE TABLE IF NOT EXISTS `dennis` (
`trid` varchar(50) NOT NULL,
`place` varchar(50) NOT NULL,
`si` varchar(50) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
then i inserted rows this way :
INSERT INTO `dennis` (`trid`, `place`, `si`) VALUES
('100', 'cochi', '3'),
('300', 'cochi', '1'),
('100', 'mumbai', '1'),
('100', 'bangalore', '2'),
('300', 'bangalore', '2'),
('300', 'mumbai', '3'),
('200', 'hyderabad', '1'),
('400', 'trivandrum', '1'),
('200', 'bangalore', '2'),
('200', 'trivandrum', '3'),
('400', 'bangalore', '2'),
('400', 'hyderabad', '3');
My problem is when i select start station as Bangalore and destination as mumbai, I am getting all the train numbers because bangalore exist for all trid ie trainid but mumbai exist only for 100 and 300.
I need a query that can return only those trid who have both mumbai and bangalore. Also the si ie Serialnumber of bangalore must be lesser than si of mumbai.
i used this query but it seems to return all the record
SELECT DISTINCT trid FROM dennis WHERE place ='mumbai' OR place='bangalore'
try this,
SELECT DISTINCT d1.trid
FROM dennis d1
INNER JOIN dennis d2 ON d2.trid=d1.trid
WHERE d1.place = 'bangalore' and d2.place = 'mumbai' AND d1.si < d2.si
hope this answers your question
SELECT d1.trid
FROM dennis d1
INNER JOIN dennis d2 ON d2.trid=d1.trid
WHERE d1.place = 'bangalore' and d2.place = 'mumbai'