Adding values to existing string - mysql

This sounds like a basic stuff but I'm running our of caffeine and my brain is seizing...
I have a table with where couple columns are set as datatype = text and contain comma separated strings, something like this
id | labels | items
------------------------------------------------
123 | Resources,Faculty Resources | 2323,97
If I know row ID can I append new values to labels and items via UPDATE or do I first need to query the table, get data, append values and then do update with new string?

A single update query can do:
update mytable
set items = concat(coalesce(concat(items, ','), ''), :new_item)
where id = :id
... where :new_item is the item you want to add and :id is the id of the target row.
The coalesce()/concat() logic takes in account the possibility that items could be null on an existing row. If that's never the case, then simply:
update mytable
set items = concat(items, ',', :new_item)
where id = :id
Note, however, that storing delimited lists in a table is bad practice, and should be generally avoided. More about this can be read in this famous SO question.

Related

MySQL: how can i push data onto existing column data?

si have a db field that i want to use to track intervals. i want to push completed intervals onto the db field when they are completed. to wit:
intervals = '10'
intervals = '1020' <-- pushing 20 onto the field
intervals = '102040' <-- pushing 40 onto the field
intervals = '102040SP' <-- pushing SP onto the field
the values will never decrement (and order doesn't really matter, if that's a factor), so i'm only looking for a way to UPDATE the field, but i have no idea how to do that because UPDATE tbl SET ... just overwrites the existing contents. i looked into CONCAT, but that works with variables the user provides, not with existing data AND additional user data. if i were to write some PSEUDO code, it might look like this:
UPDATE tbl PUSHTO intervals VALUE newInterval WHERE id='id' AND date='date'
so. can anybody help me out here? there has to be a way to do this. :)
An update with concatenation is what you want here:
UPDATE tbl
SET interval = CONCAT(interval, newInterval)
WHERE id = 'id' AND date = 'date';
If you wanted to make the update even in the event that newInterval might be null, you could try:
UPDATE tbl
SET interval = CONCAT(interval, COALESCE(newInterval, ''))
WHERE id = 'id' AND date = 'date';

MySQL Get "id" from select

I have a select statement:
SELECT id, content, name
FROM records
WHERE type = '1'
AND name = 'test';
Here's the output:
id content name
99708 10.6.252.41 server01.example.org
What I'd like to do is be able to get the id that is returned from the previous statement and USE the id as input into another statement (an UPDATE statement) that will increment the value of a single column in the same table.
An example UPDATE statement that I am wanting is:
update records SET hits = hits + 1 WHERE id = ID_FROM_SELECT;
Thanks in advance.
You can use user defined session variables for this if the SELECT is returning just one result:
SELECT #id:=id AS id, content, name
FROM records
WHERE type = '1'
AND name = 'test';
Then, on the same database session (connection), do the following:
UPDATE records
SET hits = hits + 1
WHERE id = #id;
I'm assuming you're doing something with the selected records in your app, and you're trying to save on performance by avoiding having to search for the record again in the UPDATE. Though, in that case, why not set the 'id' value as a parameter in code?
Obviously, if the SELECT is returning multiple records, this would best be done in code as I mentioned above, otherwise you're left with running the SELECT query again as a subquery:
UPDATE records
SET hits = hits + 1
WHERE id IN
(SELECT id
FROM records
WHERE type = '1'
AND name = 'test');
So, then, it makes more sense just to apply the same filter to the UPDATE instead:
UPDATE records
SET hits = hits + 1
WHERE type = '1'
AND name = 'test'
Probably this is not what you want to do.
First of all...If the query only returns 1 line, the solution provided by Marcus Adams works fine. But, if the query only returns one line, you dont need to preset the id in order to update. Just update it:
update records
set hits = hits + 1
where type = '1'
and name = 'test'
Second...If the query will not return only one record and you want to update all records returned with same values or calculations, the same code above will do what you need.
Third, if the query does not return just one record and you need to update each record returned with different value then you need to have a different approach.
I think you are not designing your system very well. If the request for update come from outside, you should have the id to be updated as a parameter of your request. For example something like:
<html>
<body>
Test
</body>
</html>
And in your update.php you have something like:
<?php
$id = $_GET['id'];
$sql = "update records set hits = hits + 1 where type = '1' and name = 'test' and id = $id";
?>
Of course, the picture I have is to small. Probably you have a reason to do this way or this is just an example. If you fill us up with more info we might be more helpful.

Query Multiple Rows in the same Table for one Variable

I have a table setup like this:
session_id | event_id | moderator | speaker_1 | speaker_2 | speaker_3 | ...keeps going to speaker_10
What I am trying to do is setup a query that searches for 1 variable "speakerid = 13245" and check rows
'moderator', 'speaker_1', 'speaker_2', 'speaker_3', 'speaker_4', 'speaker_5', 'speaker_6', 'speaker_7', 'speaker_8', 'speaker_9', 'speaker_10'
Then return every 'session_id' corresponding to any row that contains speakerid = 12345 in any of the 11 speaker rows.
I know it has something to do with an INNER JOIN but after a lot of searching I can't find anything specific enough. I've been following stackoverflow for years now and this is my first ever post.
It really sounds like you need to normalize this table and have a table of sessions/events and a table of speakers related to it through a third sesssions_speaker table. That way you don't need to change your table schema when you have an event with 12+ speakers.
That being said, you can query like this to get the result you need
SELECT session_id
FROM table
WHERE
moderator = ?
OR speaker_1 = ?
OR speaker_2 = ?
...
OR speaker_11 = ?
I think you just need to use LIKE with OR to return the rows where any field contains "speakerid = 12345":
SELECT Session_Id
FROM YourTable
WHERE Moderator Like '%speakerid = 13245%'
OR speaker_1 Like '%speakerid = 13245%'
OR ...
You should read up on database normalization as speaker_n columns are a bad sign. You probably want a Speakers table amd a "Session-Speakers" mapping table. This would certainly make your query easier, but for now you have no choice but to search all columns:
SELECT sesion_id FROM t1 WHERE
moderator = '12345'
OR speaker_1 = 12345
etc.
You can do this using in in the where clause:
select session_id
from t
where 13245 in (moderator, speaker_1, speaker_2, speaker_3, speaker_4,
speaker_5, speaker_6, speaker_7, speaker_8, speaker_9,
speaker_10)

How can I sanitize my DB from these duplicates

I have a table with the following fields:
id | domainname | domain_certificate_no | keyvalue
An example for the output of a select statement can be as:
'57092', '02a1fae.netsolstores.com', '02a1fae.netsolstores.com_1', '55525772666'
'57093', '02a1fae.netsolstores.com', '02a1fae.netsolstores.com_2', '22225554186'
'57094', '02a1fae.netsolstores.com', '02a1fae.netsolstores.com_3', '22444356259'
'97168', '02aa6aa.netsolstores.com', '02aa6aa.netsolstores.com_1', '55525772666'
'97169', '02aa6aa.netsolstores.com', '02aa6aa.netsolstores.com_2', '22225554186'
'97170', '02aa6aa.netsolstores.com', '02aa6aa.netsolstores.com_3', '22444356259’
I need to sanitize my db such that: I want to remove the domain names that have repeated keyvalue for the first domain_certificate_no (i.e, in this example, I look for the field domain_certificate_no: 02aa6aa.netsolstores.com_1, since it is number 1, and has repeated value for the key, then I want to remove the whole chain which is 02aa6aa.netsolstores.com_2 and 02aa6aa.netsolstores.com_3 and this by deleting the domain name that this chain belongs to which is 02aa6aa.netsolstores.com.
How can I automate the checking process for the whole DB. So, I have a query that checks any domain name in the pattern ('%.%.%) EDIT: AND they have share domain name (in this ex: netsolstores.com) , if it finds cert no. 1 that belongs to this domain name has a repeated key value, then delete. Otherwise no. Please, note tat, it is ok for domain_certificate_no to have repeated value if it is not number 1.
EDIT: I only compare the repeated valeues for the same second level domain name. Ex: in this question, I compare the values that share the domain name: .netsolstores.com. If I have another domain name, with sublevel domains, I do the same. But the point is that I don't need to compare the whole DB. Only the values with shared domain name (but different sub domain).
I'm not sure what happens with '02aa6aa.netsolstores.com_1' in your example.
The following keeps only the minimum id for any repeated key:
with t as (
select t.*,
substr(domain_certificate_no,
instr(domain_certificate_no, '_') + 1, 1000) as version,
left(domain_certificate_no, instr(domain_certificate_no, '_') - 1) as dcn
from t
)
select t.*
from t join
(select keyvalue, min(dcn) as mindcn
from t
group by keyvalue
) tsum
on t.keyvalue = tsum.keyvalue and
t.dcn = tsum.mindcn
For the data you provide, this seems to do the trick. This will not return the "_1" version of the repeats. If that is important, the query can be pretty easily modified.
Although I prefer to be more positive (thinking about the rows to keep rather than delete), the following should delete what you want:
with t as (
select t.*,
substr(domain_certificate_no,
instr(domain_certificate_no, '_') + 1, 1000) as version,
left(domain_certificate_no, instr(domain_certificate_no, '_') - 1) as dcn
from t
),
tokeep as (
select t.*
from t join
(select keyvalue, min(dcn) as mindcn
from t
group by keyvalue
) tsum
on t.keyvalue = tsum.keyvalue and
t.dcn = tsum.mindcn
)
delete from t
where t.id not in (select id from tokeep)
There are other ways to express this that are possibly more efficient (depending on the database). This, though, keeps the structure of the original query.
By the way, when trying new DELETE code, be sure that you stash a copy of the table. It is easy to make a mistake with DELETE (and UPDATE). For instance, if you leave out the WHERE clause, all the rows will disappear, after the long painful process of logging all of them. You might find it faster to simply select the desired results into a new table, validate them, then truncate the old table and re-insert them.

Updating an entire row with values from a row on a different table (cake/mysql)

currently I use a query like this to update a table called cats from a table called admin cats (the $id is because it's in cake, it's just a number like 1,2,3 etc). As it is I name every field (there are maybe 50) and say it like this:
update cats AS c, admin_cats set c.category=(select category from admin_cats where id=$id), [--removed 50 columns in the middle--] c.overviewImageText8=(select overviewImageText8 from admin_cats where id=$id) where c.id = $id");
I'm updating every column, so is there a way I can just say something like:
UPDATE cats SET * = SELECT * FROM admin_cats WHERE admin_cats.id = $id) WHERE cats.id IN ($id);
Of course I tried that and it doesn't work, but I want to do it where the cats row where the id matches $id will update with values from the admin_cats that has that same id. How can I do this?
For MySQL specifically, use REPLACE
REPLACE cats (<optional columns>)
SELECT <cols>
FROM admin_cats
WHERE admin_cats.id = $id;
Note: This assumes cats has a Primary Key (e.g. cats.id) that the duplicate row error can be caught, and the row replaced.
Note: other databases don't support replace or use other, similar but different syntax.