Change the column value if it fits another table - mysql

Hello to every poeple of stackoverflow community
i want to ask something to you

The type i don't know how can i compare it and to what
CREATE TABLE spawnhist (
`npctempladeld` INTEGER,
`count` INTEGER
);
INSERT INTO spawnhist
(`npctempladeld`, `count`)
VALUES
('100', '1'),
('200', '1'),
('300', '1');
CREATE TABLE npc (
`npcid` INTEGER,
`type` VARCHAR(9)
);
INSERT INTO npc
(`npcid`, `type`)
VALUES
('100', 'L2Monster'),
('200', 'L2NPC'),
('300', 'L2PET');
Update spawnhist SET `count` = `count` +1
WHERE npctempladeld IN (SELECT `npcid` FROM npc WHERE type = 'L2Monster')
SELECT * FROM spawnhist
npctempladeld | count
------------: | ----:
100 | 2
200 | 1
300 | 1
db<>fiddle here

Something like, ( what I understood at first glance)
My code is based on oracle but I believe it works the same in MySQL. Please try.
Update spawnlist sl
Set count = 2
Where exists (select 1
from npc nc
where nc.npc_id = sl.npc_templadeId
and nc.type = 'L2Monster')

Related

How do you insert a new record or update an existing if id already exists with inner join?

The goal is to insert a new record or update an existing if the id column exists. The ON DUPLICATE KEY UPDATE function seems to be a good fit but the problem I have is I want to make sure that the ID matches an ID in another table. This is for permissions. An example is:
INSERT INTO `testtable` (`id`, `user_id`, `order`, `active`)
VALUES
(1, 24, 3, 0),
(2, 24, 1, 1),
(NULL, 24, 2, 0) AS newupdate
ON DUPLICATE KEY UPDATE
order = newupdate.order,
active = newupdate.active
This works but I want to add a check where the testtable.user_id from above matches users.id from another table. I've been using this SELECT statement:
SELECT testtable.id, testtable.order, testtable.active
FROM testtable
INNER JOIN users on testtable.user_id = users.id
WHERE users.username = bob
So I can't figure out how to utilize the ON DUPLICATE KEY UPDATE with an INNER JOIN or perhaps I'm going about this all the wrong way. I search Stackoverflow and saw some suggestions to use a SELECT statement with the ON DUPLICATE KEY UPDATE but I don't understand how that passes the values. Anyway, is this possible? Thanks in advance.
UPDATE: I was able to get it working but it seems like there should be an easier/better way? Anyone have any other suggestions? This example below I'm inserting a row with id 24 which exists so the update runs and then I'm inserting a row with id NULL so it gets inserted as is.
INSERT INTO `testtable` (`id`, `user_id`, `order`, `active`)
SELECT `id`, `user_id`, `order`, `active`
FROM (SELECT
24 AS id,
(SELECT user_id FROM testtable INNER JOIN users on testtable.user_id = users.id WHERE users.username = 'bob' LIMIT 1) AS user_id,
6 AS order,
1 AS active
UNION ALL
SELECT
NULL AS id,
(SELECT user_id FROM testtable INNER JOIN users on testtable.user_id = users.id WHERE users.username = 'bob' LIMIT 1) AS user_id,
7 AS order,
1 AS active
)
AS newtable
ON DUPLICATE KEY UPDATE
order = newtable.order,
active = newtable.active
Here we have a foreign key to users and a trigger to block changing user_id.
create table users(
id int primary key,
user varchar(25));
insert into users values
(12,'Andrew'),
(24,'Bernard');
✓
✓
create table testtable (
id int ,
user_id int unique,
order_ int,
active int,
foreign key fk_user_id (user_id)
references users(id));
✓
INSERT INTO `testtable` (`id`, `user_id`, `order_`, `active`)
VALUES
(1, 24, 3, 0),
(2, 24, 1, 1),
(NULL, 24, 2, 0) AS newupdate
ON DUPLICATE KEY UPDATE
order_ = newupdate.order_,
active = newupdate.active
✓
/*delimiter $$ */
create trigger user_id_update
before update on testtable
for each row
begin
if (old.user_id <>new.user_id) then
signal SQLSTATE VALUE '45000'
SET MESSAGE_TEXT = 'user_id change forbidden';
end if ;
end ;
/* delimiter ; */
✓
✓
select * from testtable;
id | user_id | order_ | active
-: | ------: | -----: | -----:
1 | 24 | 2 | 0
update testtable
set user_id = 12 where user_id = 24;
user_id change forbidden
select * from testtable;
id | user_id | order_ | active
-: | ------: | -----: | -----:
1 | 24 | 2 | 0
db<>fiddle here

Selecting unique column values and returning corresponding values in mysql table

SlNo
UserID
points
1
001
Three
2
002
Three
3
001
Three
I have the following table named 'userdata' and I would like to get the points of just the unique usernames.
SELECT points from userdata where USERID==distinct
Is there a functionality in mysql that works similar to == ?
Use Distinct
Query
Select distinct UserId, points
From userdata;
There are some possibilities
IN clause or a INNER JOIN
Latter will be faster on big tables
CREATE TABLE userdata (
`SlNo` INTEGER,
`UserID` INTEGER,
`points` VARCHAR(5)
);
INSERT INTO userdata
(`SlNo`, `UserID`, `points`)
VALUES
('1', '001', 'Three'),
('2', '002', 'Three'),
('3', '001', 'Thr');
SELECT `points` FROM userdata WHERE `UserID` IN (SELECT `UserID` FROM userdata GROUP BY `UserID` HAVING COUNT(*) = 1)
| points |
| :----- |
| Three |
SELECT `points`
FROM userdata u1 INNER JOIN (SELECT `UserID` FROM userdata GROUP BY `UserID` HAVING COUNT(*) = 1) u2 ON u1.`UserID` = u2.`UserID`
| points |
| :----- |
| Three |
db<>fiddle here

MySQL turn JSON_ARRAY of ids into JSON_ARRAY of values [MySQL 8]

I have a JSON_ARRAY of ids in the form of [1,3,...]. Each value represents an id to a value in another table.
Table: pets
id | value
1 | cat
2 | dog
3 | hamster
Table: pet_owner
id | pets_array
1 | [1, 3]
2 | [2]
3 | []
What I want to get when I query pet_owners is the following result:
Table: pet_owner
id | pets_array
1 | ["cat", "hamster"]
2 | ["dog"]
3 | []
How do I run a sub-select on each array element to get its value?
As JSON goes, it is always a pain to handle
When you need also all that have no pets, you must left Join the owner table
CREATE TABLE pet_owner (
`id` INTEGER,
`pets_array` JSON
);
INSERT INTO pet_owner
(`id`, `pets_array`)
VALUES
('1', '[1, 3]'),
('2', '[2]'),
('3', '[]');
CREATE TABLE pets (
`id` INTEGER,
`value` VARCHAR(7)
);
INSERT INTO pets
(`id`, `value`)
VALUES
('1', 'cat'),
('2', 'dog'),
('3', 'hamster');
SELECT
t1.id,
JSON_ARRAYAGG(
p.`value`
) AS pets_array
FROM(
SELECT *
FROM pet_owner ,
JSON_TABLE(
pet_owner.pets_array , "$[*]"
COLUMNS(IDs int PATH "$" NULL ON ERROR DEFAULT '0' ON EMPTY )
) AS J_LINK ) t1
LEFT JOIN pets p ON p.id =t1.IDs
GROUP BY
t1.id
;
id | pets_array
-: | :-----------------
1 | ["cat", "hamster"]
2 | ["dog"]
db<>fiddle here
A normalized Table would spare you to convert the data into usable columns.
You can join on json_contains(), then re-aggregate:
select po.id, json_arrayagg(p.value) as owners
from pet_owner po
left join pets p on json_contains(po.pets_array, cast(p.id as char))
group by po.id
Note that, unlike most (if not all!) other databases, MySQL does not guarantee the ordering of elements in an array generated by json_arrayagg(): that's just a fact we have to live with as of the current version.

Is it possible to use keys as columns and values as values for a key/value database structure? [duplicate]

This question already has answers here:
How can I return pivot table output in MySQL?
(10 answers)
Closed 2 years ago.
I need to query some data from a MySQL key value table but I want get a "normal" table as result with specified keys as columns.
Example of my table USERS:
ID, user_id, key, value
----------------------------------
1 1 first_name Peter
2 1 last_name Sputnick
3 2 first_name Jan
4 2 last_name Putgraver
5 2 country Netherlands
I want this as query result:
ID, first_name, last_name
----------------------------
1 Peter Sputnick
2 Jan Putgraaf
Is there a good and efficient way to achieve this? Note that I don't want to include the country column in my result.
I need this because i need to join this data with data from another table and i don't want to use a sub query for each field i need. So I don't want to do something like this:
SELECT *,
(SELECT value
FROM users
WHERE user_id = o.user_id
AND key = first_name),
(SELECT value
FROM users
WHERE user_id = o.user_id
AND key = last_name),
FROM orders o
You can use conditional aggregation:
select
id,
max(case when key = 'fist_name' then value end) first_name,
max(case when key = 'last_name' then value end) last_name
from users
group by id
for thsi you must use conditional aggregation,
CREATE TABLE USERS (
`ID` VARCHAR(6),
`user_id` VARCHAR(9),
`key` VARCHAR(10),
`value` VARCHAR(11)
);
INSERT INTO USERS
(`ID`, `user_id`, `key`, `value`)
VALUES
('1', '1', 'first_name', 'Peter'),
('2' , '1', 'last_name', 'Sputnick'),
('3', '2', 'first_name', 'Jan'),
('4', '2', 'last_name', 'Putgraver'),
('5', '2', 'country', 'Netherlands');
SELECT user_id
, MAX(IF(`key` ='first_name',`value`,NULL )) fisrt_name
, MAX(IF(`key` ='last_name',`value`,NULL )) last_name
FROM USERS
GROUP BY user_id;
user_id | fisrt_name | last_name
:------ | :--------- | :--------
1 | Peter | Sputnick
2 | Jan | Putgraver
db<>fiddle here
If you want all keys you must use a pivot table

Select last distinct records in mysql

I have a table in mysql have a lot of data.i want to display only distinct and last saved data...here is what i have
CREATE TABLE amounts(
id MEDIUMINT NOT NULL AUTO_INCREMENT,
bank_id INT,
amount INT,
PRIMARY KEY (id)
) ENGINE=MyISAM;
INSERT INTO `amounts` (`id`, `bank_id`, `amount`) VALUES (NULL, '1', '100'),
(NULL, '2', '200'),(NULL, '3', '300'),(NULL, '1', '500'),(NULL, '2', '600'),
(NULL, '1', '800'),(NULL, '2', '50');
I want result like this
bank_id amount
1 800
2 50
3 300
how will be select query for this?
Use a self join. This is almost always faster than a subquery.
SELECT a.*
FROM amounts a LEFT JOIN amounts b ON a.bank_id = b.bank_id AND a.id < b.id
WHERE b.id IS NULL
See a demo
This should do it:
SELECT a.bank_id,
b.amount
FROM (SELECT bank_id,
Max(id) AS id
FROM amounts
GROUP BY bank_id) a
INNER JOIN amounts b
ON b.id = a.id
Result
| BANK_ID | AMOUNT |
--------------------
| 1 | 800 |
| 2 | 50 |
| 3 | 300 |
See a demo
You could use a subquery where you select max IDs for every bank_id, then you select all rows whose IDs are returned by this subquery:
SELECT amounts.*
FROM amounts
WHERE id IN (select max(id)
from amounts
group by bank_id)
ORDER BY bank_id
Please see this fiddle.