I have a table in MySQL with this format: (time = timestamp on insert)
id | tid | uid | time
31 | 1 | 14 | 2011-05-19 05:42:37 //start timestamp)
41 | 1 | 14 | 2011-05-19 07:18:42 //stop timestamp)
45 | 1 | 14 | 2011-05-19 07:18:49 //start timestamp)
46 | 1 | 14 | 2011-05-19 07:28:42 //stop timestamp)
What I need is to make a select that adds the time differences like this
(41 - 31) + (46 - 45) (i'm using the id's instead of the actual time values to better understand what I need to do )
something like SELECT (something that does this) AS TotalTimeSpent WHERE tid = '1'
If you insist on using this table layout (and I really hope you change your mind, it is truly horrific), you can do it with cursors in a stored procedure.
Pseudo-code would be something like this:
CREATE PROCEDURE gettotaltime()
BEGIN
DECLARE total, curr, prev DATETIME;
DECLARE odd INT DEFAULT 1;
DECLARE done INT DEFAULT 0;
DECLARE c CURSOR FOR SELECT time FROM tbl;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN c;
read_loop: LOOP
FETCH c INTO curr;
IF odd=0 THEN
SET total=dateadd(total,datediff(curr,prev)); -- or something similar, I forget
END IF;
SET prev=curr;
SET odd=1-odd;
IF done THEN
LEAVE read_loop;
END IF;
END LOOP;
CLOSE c;
SELECT total;
END;
Related
A friend of mine wants to check if all the rows, of each of the columns of a table, have the same value.
If they do, then print the value.
Else just print an empty string or null or something.
Imagine this table for example:
+--------+----------+-----+
| Name | Lastname | Age |
+--------+----------+-----+
| Peter | White | 30 |
| Marry | Jane | 30 |
| John | Doe | 30 |
+--------+----------+-----+
The result of the wanted query would output the following:
+--------+----------+-----+
| Name | Lastname | Age |
+--------+----------+-----+
| NULL | NULL | 30 |
+--------+----------+-----+
I tried to create a function where I would get the columns of a given table, loop through each column name and execute a query. But since I am not familiar with Mysql I obviously miss something out and I can't figure out how to achieve what I'm trying to do here.
DROP PROCEDURE IF EXISTS test;
DELIMITER //
create procedure test()
begin
declare i int(11);
declare col_name varchar(50);
declare num_rows int(11);
DECLARE col_names CURSOR FOR
SELECT column_name
FROM information_schema.columns
WHERE table_name='name_of_my_table' and table_schema='name_of_db';
select FOUND_ROWS() as num_rows;
set i = 1;
open col_names;
the_loop: LOOP
IF i > num_rows THEN
CLOSE col_names;
LEAVE the_loop;
END IF;
FETCH col_names
INTO col_name;
-- Here I would like to perform a query for each column
select count(*), col_name from name_of_my_table group by col_name;
-- Then I was thinking of making an if/ else condition to check
-- if I get more than 1 result per column, implying that
-- not all rows have the same value for this column.
SET i = i + 1;
END LOOP the_loop;
CLOSE col_names;
END//
DELIMITER ;
call test;
What this outputs is the count and the column name of the last column found, which does make sense.
I am not sure if what I am trying to do is possible with Mysql only, I can easily do that in PHP but I am wondering if I can do that with a single query as well.
Try the below query.
select if(count(distinct(Name))=1,Name,null), if(count(distinct(Lastname))=1,Lastname,null), if(count(distinct(Age))=1,Age,null)
from your_table;
i have a single table with duplicate id.i created a table with distinct id and count of that id i want to compare and update based on that id
+----+-------+
| id | value |
+----+-------+
| 1 | 1:a |
| 1 | 1 |
| 1 | 2:b |
+----+-------+
expected output
+----+-------+
| id | value |
+----+-------+
| 1 | 1:a 1 |
| 1 | 2:b |
+----+-------+
what i have tried is i have written a procedure which executes perfectly but it prematurely exist the loop. i don't know why it exits can anyone guide me
DELIMITER //
CREATE PROCEDURE value_merge()
BEGIN
DECLARE v_val INTEGER DEFAULT 0;
DECLARE i INTEGER DEFAULT 1;
DECLARE row_cou INTEGER DEFAULT 0;
DECLARE colan INTEGER DEFAULT 0;
DECLARE mm_num varchar(20) DEFAULT "";
DECLARE merge_value varchar(132000) DEFAULT "";
DEClARE merge_cursor CURSOR FOR
SELECT Material_Number,cou FROM zz_plant_data_given_table_form_work_bhai where flag='y';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_val = 1;
OPEN merge_cursor;
get_loop: LOOP
FETCH merge_cursor INTO mm_num,row_cou;
IF v_val = 1 THEN
LEAVE get_loop;
END IF;
while i<=row_cou do
SELECT Basic_Data_Text INTO merge_value FROM `zz_plant_data_given_table_form_work` where Material_Number=mm_num and seq=row_cou;
set colan=ROUND ((LENGTH(merge_value)- LENGTH( REPLACE (merge_value, ":", "") )) / LENGTH(":"));
IF colan>0 THEN
set row_cou=row_cou-1;
ELSE
update `zz_plant_data_given_table_form_work` set sts='y' where Material_Number=mm_num and seq=row_cou;
set row_cou=row_cou-1;
update zz_plant_data_given_table_form_work set Basic_Data_Text=concat(Basic_Data_Text,' ',merge_value) where Material_Number=mm_num and seq=row_cou;
END IF;
END while;
update zz_plant_data_given_table_form_work_bhai set flag='' where Material_Number=mm_num;
END LOOP get_loop;
CLOSE merge_cursor;
END//
DELIMITER
;
This two sentences fires the NOT FOUND handler, so I suggest use another type of query to get merge_value
Change it for:
set merge_value = ( SELECT Basic_Data_Text
FROM `zz_plant_data_given_table_form_work`
where Material_Number=mm_num
and seq=row_cou
limit 1 ); /* to prevent errors*/
I was working on a stored procedure to update the order field in a product table.
It works only the problem now is the the last item in the loop(cur), is increased twice instead of once (so dubbeled). Like so:
+-----------------+
|product + order |
|_id | |
| | |
| 1 | 0 |
| 2 | 1 |
| etc.. | etc..|
| 36 | 35 |
| 37 | 36 |
| 38 | 38 |
| |
+-----------------+
I cant figure out why. The link table(CategoryProduct) in this case goes to 38 with a category_id of 2 CALL curorder(2);
Stored procedure:
DELIMITER //
CREATE PROCEDURE curorder(
IN catid INT
)
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE i INT DEFAULT 0;
DECLARE p INT;
DECLARE cur CURSOR FOR SELECT product_id FROM test.CategoryProduct WHERE category_id = catid;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN cur;
read_loop: LOOP
FETCH cur INTO p;
UPDATE `test`.`Product` SET `order` = i WHERE `Product`.`product_id` =p;
SET i = i + 1;
IF done THEN
LEAVE read_loop;
END IF;
END LOOP;
CLOSE cur;
END //
DELIMITER ;
The Database is a Mysql Database. Any suggestions for improving the procedure are always welcome.
Thanks in advance.
EDIT:
I already tried to place the SET i STATEMENT beneath the IF STATEMENT but with no result.
You should put:
IF done THEN
LEAVE read_loop;
END IF;
Above your update statement, the last time mysql walks trough the loop is uses the old variables because there is no new 'p'. but i is incremented.
I good way to debug stored procedures is with a log table:
CREATE TABLE procedureLog
(
id INTEGER AUTO_INCREMENT,
description TEXT,
PRIMARY KEY (id)
);
For this case you can log the update parameters with the follow query:
INSERT INTO `test`.`procedureLog` (`id` ,`description`) VALUES (null, CONCAT('id: ', CAST(p as CHAR), ' order: ', CAST(i as CHAR)));
Good luck!
I tried some, but I couldn't find the solution, somehow I managed to get this result.
Here is the query:
DELIMITER ##
CREATE PROCEDURE test1(start_date DATE,end_date DATE)
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE a INT;
DECLARE present INT;
DECLARE total INT;
-- Declare the cursor
DECLARE id CURSOR
FOR
SELECT staff_id FROM ost_staff;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
-- Open the cursor
DROP TEMPORARY TABLE IF EXISTS reports;
CREATE TEMPORARY TABLE IF NOT EXISTS reports
(
staff_id INT(10),
present INT(10),
total INT(10)
);
OPEN id;
read_loop: LOOP
FETCH id INTO a;
IF done THEN
LEAVE read_loop;
END IF;
INSERT INTO reports(staff_id,present,total)
SELECT (COUNT(I.interval_start)) AS present, DATEDIFF(DATE_ADD(end_date,INTERVAL 1 DAY),start_date) AS total
FROM effort_frequency E
RIGHT OUTER JOIN time_intervals I ON I.interval_start = E.log_date
AND E.staffid=a AND E.log_date BETWEEN start_date AND end_date
LEFT OUTER JOIN ost_holidays H ON H.holiday_date = I.interval_start
WHERE DATE_FORMAT(I.interval_start,'%a') = 'Sun' OR H.holiday_date = I.interval_start OR E.total_effortspent IS NOT NULL;
-- Close the cursor
END LOOP;
CLOSE id;
END ##
I got the below result:
+----------+-----------------+
| staff_id | present | total |
+----------+---------+-------+
| (NULL) | 23 | 24 |
| (NULL) | 22 | 24 |
+----------+---------+-------+
I'm getting (NULL) for staff_id, How can I get the staff_id's there ?
I tried using declared variable 'a' in insert statement, but at that time I got only staff_id, I didn't get the other 2 fields, I can't get the staff_id from the select inside insert statement coz there is some problem.
Now what i need is I need to insert the staff_id from the variable 'a' into that temporary table.
note: I'm really new to this stored procedure, but somehow managed till here, Its good if I get some detail on how to use the Select inside Insert including the solution for this.
Try this -
SELECT a, (COUNT(I.interval_start)) AS present, DATEDIFF(DATE_ADD(end_date,INTERVAL 1 DAY),start_date) AS total
Your INSERT requires three fields, but your SELECT statement only selects two: present and total .
Try:
SELECT E.staffid, (COUNT(I.interval_start))
AS present, DATEDIFF(DATE_ADD(end_date,INTERVAL 1 DAY),start_date) AS total
For instance, if I have data in a column like this
data
I love book
I love apple
I love book
I hate apple
I hate apple
How can I get result like this
I = 5
love = 3
hate = 2
book = 2
apple = 3
Can we achieve this with MySQL?
Here is a solution only using a query:
SELECT SUM(total_count) as total, value
FROM (
SELECT count(*) AS total_count, REPLACE(REPLACE(REPLACE(x.value,'?',''),'.',''),'!','') as value
FROM (
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(t.sentence, ' ', n.n), ' ', -1) value
FROM table_name t CROSS JOIN
(
SELECT a.N + b.N * 10 + 1 n
FROM
(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) a
,(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) b
ORDER BY n
) n
WHERE n.n <= 1 + (LENGTH(t.sentence) - LENGTH(REPLACE(t.sentence, ' ', '')))
ORDER BY value
) AS x
GROUP BY x.value
) AS y
GROUP BY value
Here is the full working fiddle: http://sqlfiddle.com/#!2/17481a/1
First we do a query to extract all words as explained here by #peterm(follow his instructions if you want to customize the total number of words processed). Then we convert that into a sub-query and then we COUNT and GROUP BY the value of each word, and then make another query on top of that to GROUP BY not grouped words cases where accompanied signs might be present. ie: hello = hello! with a REPLACE
If you want to perform such kind of text analysis, I would recommend using something like lucene, to get the termcount for each term in the document.
This query is going to take a long time to run if your table is of any decent size. It may be better to keep track of the counts in a separate table and update that table as values are inserted or, if real time results are not necessary, to only run this query every so often to update the counts table and pull your data from it. That way, you're not spending minutes to get data from this complex query.
Here's what I've for you so far. It's a good start. The only thing you need to do is modify it to iterate through the words in each row. You could use a cursor or a subquery.
Create test table:
create table tbl(str varchar(100) );
insert into tbl values('data');
insert into tbl values('I love book');
insert into tbl values('I love apple');
insert into tbl values('I love book');
insert into tbl values('I hate apple');
insert into tbl values('I hate apple');
Pull data from test table:
SELECT DISTINCT str AS Word, COUNT(str) AS Frequency FROM tbl GROUP BY str;
create a user defined function like this and use it in your query
DELIMITER $$
CREATE FUNCTION `getCount`(myStr VARCHAR(1000), myword VARCHAR(100))
RETURNS INT
BEGIN
DECLARE cnt INT DEFAULT 0;
DECLARE result INT DEFAULT 1;
WHILE (result > 0) DO
SET result = INSTR(myStr, myword);
IF(result > 0) THEN
SET cnt = cnt + 1;
SET myStr = SUBSTRING(myStr, result + LENGTH(myword));
END IF;
END WHILE;
RETURN cnt;
END$$
DELIMITER ;
Hope it helps
Refer This
Split-string procedure is not my job. You can find it here
http://forge.mysql.com/tools/tool.php?id=4
I wrote you the rest of code.
drop table if exists mytable;
create table mytable (
id int not null auto_increment primary key,
mytext varchar(1000)
) engine = myisam;
insert into mytable (mytext)
values ('I love book,but book sucks!What do you,think about it? me too'),('I love apple! it rulez.,No, it sucks a lot!!!'),('I love book'),('I hate apple!!! Me too.,!'),('I hate apple');
drop table if exists mywords;
create table mywords (
id int not null auto_increment primary key,
word varchar(50)
) engine = myisam;
delimiter //
drop procedure if exists split_string //
create procedure split_string (
in input text
, in `delimiter` varchar(10)
)
sql security invoker
begin
declare cur_position int default 1 ;
declare remainder text;
declare cur_string varchar(1000);
declare delimiter_length tinyint unsigned;
drop temporary table if exists SplitValues;
create temporary table SplitValues (
value varchar(1000) not null
) engine=myisam;
set remainder = input;
set delimiter_length = char_length(delimiter);
while char_length(remainder) > 0 and cur_position > 0 do
set cur_position = instr(remainder, `delimiter`);
if cur_position = 0 then
set cur_string = remainder;
else
set cur_string = left(remainder, cur_position - 1);
end if;
if trim(cur_string) != '' then
insert into SplitValues values (cur_string);
end if;
set remainder = substring(remainder, cur_position + delimiter_length);
end while;
end //
delimiter ;
delimiter //
drop procedure if exists single_words//
create procedure single_words()
begin
declare finish int default 0;
declare str varchar(200);
declare cur_table cursor for select replace(replace(replace(replace(mytext,'!',' '),',',' '),'.',' '),'?',' ') from mytable;
declare continue handler for not found set finish = 1;
truncate table mywords;
open cur_table;
my_loop:loop
fetch cur_table into str;
if finish = 1 then
leave my_loop;
end if;
call split_string(str,' ');
insert into mywords (word) select * from splitvalues;
end loop;
close cur_table;
end;//
delimiter ;
call single_words();
select word,count(*) as word_count
from mywords
group by word;
+-------+------------+
| word | word_count |
+-------+------------+
| a | 1 |
| about | 1 |
| apple | 3 |
| book | 3 |
| but | 1 |
| do | 1 |
| hate | 2 |
| I | 5 |
| it | 3 |
| lot | 1 |
| love | 3 |
| me | 2 |
| No | 1 |
| rulez | 1 |
| sucks | 2 |
| think | 1 |
| too | 2 |
| What | 1 |
| you | 1 |
+-------+------------+
19 rows in set (0.00 sec)
The code must be improved in order to consider any punctuation but this is the general idea.