Update table data using foreign key - mysql

I have two tables structure like below
Table1
Serial | Src | Albumid(primarykey)
________|__________________|________
1 | /root/wewe.jpg | 20
2 | /root/wewe.jpg | 21
3 | /root/wewe.jpg | 21
4 | /root/wewe.jpg | 23
5 | /root/wewe.jpg | 18
Table2
Albumid | Albumname | AlbumCover //albumid is secondary key ref. to first table
________|__________________|________
20 | AAA | null
21 | bbb | null
31 | vcc | null
42 | ddd | null
18 | eee | null
I followed this POST two update my Albumcover in Table2 using Serial no. of first table..
create proc AddCover #Serial int
as
Begin
update Table1 set albumcover='somthing' where table1.serial = #Serial
end
Can i do like this using foregin key constraint??

You'll need to do the update on Table2. To tell it to have a condition based on values from table1, check this post for examples:
MySQL - UPDATE query based on SELECT Query

Related

Best Approach to correct column with different spellings in mysql

I have a table with column that has data with spelling errors.
Like:
apple, appl, aple
bana, banana, banna
cat, cot, cta
I would like to correct all error spelling to single correct ones. There are thousands of rows.
What would be the best approach to correct this issue where I wouldn't have to update each spelling errors manually?
I have added status iscorrect 'Y' for correct ones.
Here's a thought, using SOUNDEX. SOUNDEX is really a lousy function, and certainly no panacea, but it might reduce a data set comprising thousands of errors to a data set comprising hundreds of errors.
For the rest, we can look at things like Levenshtein distance, but ultimately, you're going to need a manual approach to some extent...
DROP TABLE IF EXISTS bad_data;
CREATE TABLE bad_data
(id SERIAL PRIMARY KEY
,string VARCHAR(12) NOT NULL
);
INSERT INTO bad_data (string) VALUES
('apple'),
('appl'),
('aple'),
('bana'),
('banana'),
('banna'),
('cat'),
('cot'),
('cta');
DROP TABLE IF EXISTS good_data;
CREATE TABLE good_data
(id SERIAL PRIMARY KEY
,string VARCHAR(12) NOT NULL UNIQUE
);
INSERT INTO good_data(string) VALUES
('apple'),
('banana'),
('cat');
SELECT *
FROM bad_data x
JOIN good_data y ON SOUNDEX(x.string) = SOUNDEX(y.string);
+----+--------+------+--------+
| id | string | id | string |
+----+--------+------+--------+
| 1 | apple | 1 | apple |
| 2 | appl | 1 | apple |
| 3 | aple | 1 | apple |
| 4 | bana | 2 | banana |
| 5 | banana | 2 | banana |
| 6 | banna | 2 | banana |
| 7 | cat | 3 | cat |
| 8 | cot | 3 | cat |
| 9 | cta | 3 | cat |
+----+--------+------+--------+

SQL query - Fetch data from one column separated by comma and display it by row

I have a problem with fetching data separated by a comma. I want the
Here is my problem
Table
ID | TDNO | PREVIOUS_TD |
1 | 14 | 13,12,11 |
2 | 23 | 45,12 |
3 | 32 | 89 |
4 | 55 | NEW |
I want to have a result like this. Example when the user will choose 14 in TD the result should be like this:
ID | TD |
1 | 14 |
2 | 13 |
3 | 12 |
4 | 11 |
And when the user will choose 32 in TD the result should be like this:
ID | TD |
1 | 32 |
2 | 89 |
when the user will select 23 the result should be like this:
ID | TD |
1 | 23 |
2 | 45 |
3 | 12 |
how to achieve this?
You might try a stored procedure or function in your version of SQL. This is MySql pseudo code and could be very buggy. Some SQL flavors do not support returning tables:
create function returnCommaSepList (IN myId INT)
begin
--
-- is mtId in the source table?
SET #previousTD = (
select PREVIOUS_TD
from TheTable
where ID = myId
)
--
-- if the result is NULL then id was not in the table, return
if #previousTD IS NULL then return
--
-- create a temporary table
create table #temp (
id INT primary key autoincrement,
td int
)
--
-- add myId to the temp table
insert into #temp (td) values(myId)
--
-- prepare to do the string handling. Step through
-- #previousTD looking for commas
SET #startPos = 0
SET #commaPos = LOCATE(',', #previousTD, #startPos)
--
-- #commaPos will be NULL if the string is NULL
if #commaPos IS NULL then return
--
-- #commaPos will be 0 if there are no commas in the string
if #commaPos = 0 then
SET #previousTD = TRIM(#previousTD)
--
-- if #previousTD is empty then return
if LENGTH(#previousTD) = 0 then return
--
-- #previousTD has something in it that is not a comma.
-- try to insert it and return
insert into #temp (td) values(#previousTD)
select * from #temp order bu id
return
endif
--
-- should have a #previousTD with at least 1 comma
while #commaPos > 0
begin
SET #item = substring(#previousTD, #startPos, #commaPos)
insert into #temp (td) values(TRIM(#item))
SET #startPos = #commaPos + 1
SET #commaPos = LOCATE(',', #previousTD, #startPos)
end
select * from #temp order bu id
end
In order to make your database, you need to create a new table which has Id of Td and tdNos and have relationships with this. for example:
Table TdNos
ID | TDNO | PREVIOUS_TD |
1 | 14 | 13,12,11 |
2 | 23 | 45,12 |
3 | 32 | 89 |
4 | 55 | NEW |
Table TdNoHistory
TdID|Priority| PREVIOUS_TD |
1 | 1 | 13 |
1 | 2 | 12 |
1 | 3 | 11 |
2 | 1 | 45 |
2 | 2 | 12 |
3 | 1 | 89 |
Which for the second table the combination of TdId and Priority are the primary key and it has a relation with table TdNos through TdId column

mysql: delete rows between repeating specific values

SQL rookie here. I have a broken punch in/out type table with millions of records fed by a legacy bad app that did not check for previous logins/logouts before merrily inserting another duplicate record. The app is fixed but I need to sanitize the table to retain the historical data so it can be fed into future reports.
In a nutshell, I'm trying to keep each minimum login row followed by the next minimum logout row and discard everything else between. The bad app allowed both duplicate logins AND logouts... grrrr.
Every "duplicate row" type question I've searched for here doesn't seem to apply to this type of grouping situation. From being a long time SO lurker I know you guys would like to see what I've already tried but have already tried tens of goofy query attempts that aren't coming close. Any guidance would be greatly appreciated.
Here's the table and what I'm trying to do and the fiddle with schema
+---------------------+-------+-------------+---------------+
| calldate | agent | etype | uniqueid |
+---------------------+-------+-------------+---------------+
| 2018-02-02 19:26:47 | 501 | agentlogin | 1517599607.71 |
| 2018-02-02 19:26:55 | 501 | agentlogin | 1517599615.72 |<-- delete
| 2018-02-02 19:27:32 | 501 | agentlogoff | 1517599652.73 |
| 2018-02-02 19:27:43 | 501 | agentlogin | 1517599663.74 |
| 2018-02-02 19:28:24 | 501 | agentlogoff | 1517599704.75 |
| 2018-02-02 19:29:02 | 501 | agentlogoff | 1517599742.76 |<-- delete
| 2018-02-02 19:29:39 | 501 | agentlogoff | 1517599778.77 |<-- delete
| 2018-02-02 19:34:54 | 501 | agentlogin | 1517600094.80 |
| 2018-02-02 19:35:23 | 501 | agentlogin | 1517600122.81 |<-- delete
| 2018-02-02 19:35:49 | 501 | agentlogin | 1517600149.82 |<-- delete
| 2018-02-02 19:36:04 | 501 | agentlogoff | 1517600164.83 |
| 2018-02-02 19:36:08 | 501 | agentlogoff | 1517600168.84 |<-- delete
+---------------------+-------+-------------+---------------+
I would create a copy of the table with an auto_increment column. This way you can compare two neighbor rows more easily and more efficiently.
Find in the new table the rows which have the same agent and etype as in the previous row and join the result with the original table using the unique column in a DELETE statement.
create table tmp (
`id` int unsigned auto_increment primary key,
`calldate` datetime,
`uniqueid` varchar(32),
`agent` varchar(80),
`etype` varchar(80)
) as
select null as id, calldate, uniqueid, agent, etype
from test
order by agent, calldate, uniqueid
;
delete t
from tmp t1
join tmp t2
on t2.id = t1.id + 1
and t2.agent = t1.agent
and t2.etype = t1.etype
join test t on t.uniqueid = t2.uniqueid;
drop table tmp;
Demo: http://sqlfiddle.com/#!9/3e96b/2
You should however first have an index on uniqueid.
Here you go:
select calldate,agent,etype,uniqueid
from test as t1
where not exists
(select *
from
test as t2
where t2.agent=t1.agent
and t2.etype=t1.etype
and t2.uniqueid<t1.uniqueid
and t2.uniqueid>ifnull((select max(uniqueid )
from test t3
where t3.agent=t1.agent
and t3.etype<>t1.etype
and t3.uniqueid<t1.uniqueid),0)
)
order by uniqueid;
http://sqlfiddle.com/#!9/149802/16

Count the rows of a table, while checking if the value is NULL or not and grouping the results by the values of another column

I am stuck trying to find a solution to my silly little problem.
The MySQL table looks as follows:
-- Create a table that will record all AdCamp hits
CREATE TABLE `advertising_campaign_hits` (
`adcamp_hit_id` INT NOT NULL AUTO_INCREMENT,
`adcamp_id` INT,
`customer_id` INT,
`recorded_at` DATETIME,
PRIMARY KEY (`adcamp_hit_id`)
) ENGINE=MyISAM;
Example values would look like this:
a_h_id | a_id | c_id | ...
1 | 1 | 1 | ...
2 | 1 | 2 | ...
3 | 1 | 3 | ...
4 | 1 | 0 | ...
5 | 1 | 0 | ...
6 | 2 | 1 | ...
7 | 2 | 0 | ...
The goal here is to count the number of hits for each of the advertising campaigns, but divide them into two groups of KnownCustomers and UnknownCustomers and then further divide them each by adcamp_id.
So the results I would expect to get are:
adcamp_id | HitsByKnown | HitsByUnknown
1 | 3 | 2
2 | 1 | 1
I am currently stuck in where I can get SQL to give me two separate rows for each of the adcamps, but the results of COUNT(*) list all of my entries.
So what I get is:
adcamp_id | HitsByKnown | HitsByUnknown
1 | 4 | 3
2 | 4 | 3
I can't figure out how to split it all up.
select adcamp_id,sum(if(customer_id>0,1,0)) as HitsByKnown,sum(if(customer_id=0,1,0)) as HitsByUnknown from advertising_campaign_hits group by adcamp_id
or even easier:
select adcamp_id,sum(customer_id!=0) as HitsByKnown,sum(customer_id=0) as HitsByUnknown from advertising_campaign_hits group by adcamp_id

select from view -> update OR insert into table

I want to select data from a mysql-view which collects and joins data from "federated"-tables.
This data should be inserted into a table which looks very similar to the view.
an example would be:
table where data needs to be inserted or updated:
insertTable
+----+-----------+------+-------------+
| id | foreignId | data | foreignData |
+----+-----------+------+-------------+
| 1 | a | 111 | aaa |
| 2 | b | 222 | bbb |
+----+-----------+------+-------------+
the view where the data comes from:
dataView
+-----------+-------------+
| foreignId | foreignData |
+-----------+-------------+
| a | AAA |
| b | BBB |
| c | CCC |
+-----------+-------------+
insertTable
+----+-----------+------+-------------+
| id | foreignId | data | foreignData |
+----+-----------+------+-------------+
| 1 | a | 111 | AAA |
| 2 | b | 222 | BBB |
| 3 | b | | CCC |
+----+-----------+------+-------------+
and at this point i think i need a stored procedure which does following written in pseudo code
$result = SELECT * FROM dataView;
foreach $result as $row {
if(SELECT COUNT(*) FROM inserTable WHERE foreignId=$row[foreignId]>0)
UPDATE insertView SET foreignData = $row[foreignData] WHERE foreignId=$row[foreignId];
else
INSERT INTO insertView (id, foreignId, foreignData) VALUES (null,$row[foreignId],$row[foreignData];
}
You can use REPLACE query.
REPLACE INTO insertView (id, foreignId, foreignData) VALUES (null,$row[foreignId],$row[foreignData];
From mysql documentation
REPLACE works exactly like INSERT, except that if an old row in the
table has the same value as a new row for a PRIMARY KEY or a UNIQUE
index, the old row is deleted before the new row is inserted. See
Section 13.2.5, “INSERT Syntax”.
PRIMARY KEY or a UNIQUE index not specified it will insert a new row.
So no need to SELECT checking.
The magic which is ideal for this problem was ON DUPLICATE KEY UPDATE
In my example the solution would look like this:
INSERT INTO insertTable
(
`foreignId`,
`foreignData`
)
SELECT
`dataView`.`foreignId`,
`dataView`.`foreignData`
FROM
`dataView`
ON DUPLICATE KEY UPDATE
`foreignId` = `dataView`.`foreignId`,
`foreignData` = `dataView`.`foreignData`;