Concanate rows on Sybase by Id - sybase-ase

I´m having results on a table like:
What I wanted to do is have result like:
How can I do this because Sybase don t have concatenate method?

setup:
create table mytab
(id varchar(10)
,b varchar(30))
go
insert mytab values ('233.263','DDDD')
insert mytab values ('233.263','AAAAAQ')
insert mytab values ('233.283','22223')
insert mytab values ('233.283','333333')
go
-- #lists will hold intermediate results
create table #lists
(id varchar(10)
,b_list varchar(1000))
go
declare our cursor:
NOTE: OP did not state how the b column values are to be sorted so we'll stick with alphabetical sorting for this example.
declare mycur cursor
for
select id,b
from mytab
order by id,b
for read only
go
loop through cursor, appending b values to #b_list for each distinct id:
declare #id varchar(10),
#id_old varchar(10),
#b varchar(30),
#b_list varchar(1000)
select #id_old = NULL
open mycur
fetch mycur into #id, #b
while ##sqlstatus = 0
begin
-- if new #id value, save old #id/#b_list pair
if #id != isnull(#id_old,'UNDEFINED')
begin
if #b_list is not NULL
begin
insert #lists values (#id_old, #b_list)
end
select #id_old = #id,
#b_list = NULL
end
select #b_list = #b_list + case when #b_list is not NULL then '|' end + #b
fetch mycur into #id, #b
end
-- save last #id/#b_list pair
if #b_list is not NULL
begin
insert #lists values (#id, #b_list)
end
close mycur
deallocate cursor mycur
go
display results:
select * from #lists
go
id b_list
------- ------------
233.263 AAAAAQ|DDDD
233.283 22223|333333

Related

MYSQL query for comma separated output from exiting table [duplicate]

I have table :
id | name
1 | a,b,c
2 | b
i want output like this :
id | name
1 | a
1 | b
1 | c
2 | b
If you can create a numbers table, that contains numbers from 1 to the maximum fields to split, you could use a solution like this:
select
tablename.id,
SUBSTRING_INDEX(SUBSTRING_INDEX(tablename.name, ',', numbers.n), ',', -1) name
from
numbers inner join tablename
on CHAR_LENGTH(tablename.name)
-CHAR_LENGTH(REPLACE(tablename.name, ',', ''))>=numbers.n-1
order by
id, n
Please see fiddle here.
If you cannot create a table, then a solution can be this:
select
tablename.id,
SUBSTRING_INDEX(SUBSTRING_INDEX(tablename.name, ',', numbers.n), ',', -1) name
from
(select 1 n union all
select 2 union all select 3 union all
select 4 union all select 5) numbers INNER JOIN tablename
on CHAR_LENGTH(tablename.name)
-CHAR_LENGTH(REPLACE(tablename.name, ',', ''))>=numbers.n-1
order by
id, n
an example fiddle is here.
I have take the reference from here with changed column name.
DELIMITER $$
CREATE FUNCTION strSplit(x VARCHAR(65000), delim VARCHAR(12), pos INTEGER)
RETURNS VARCHAR(65000)
BEGIN
DECLARE output VARCHAR(65000);
SET output = REPLACE(SUBSTRING(SUBSTRING_INDEX(x, delim, pos)
, LENGTH(SUBSTRING_INDEX(x, delim, pos - 1)) + 1)
, delim
, '');
IF output = '' THEN SET output = null; END IF;
RETURN output;
END $$
CREATE PROCEDURE BadTableToGoodTable()
BEGIN
DECLARE i INTEGER;
SET i = 1;
REPEAT
INSERT INTO GoodTable (id, name)
SELECT id, strSplit(name, ',', i) FROM BadTable
WHERE strSplit(name, ',', i) IS NOT NULL;
SET i = i + 1;
UNTIL ROW_COUNT() = 0
END REPEAT;
END $$
DELIMITER ;
My variant: stored procedure that takes table name, field names and delimiter as arguments. Inspired by post http://www.marcogoncalves.com/2011/03/mysql-split-column-string-into-rows/
delimiter $$
DROP PROCEDURE IF EXISTS split_value_into_multiple_rows $$
CREATE PROCEDURE split_value_into_multiple_rows(tablename VARCHAR(20),
id_column VARCHAR(20), value_column VARCHAR(20), delim CHAR(1))
BEGIN
DECLARE id INT DEFAULT 0;
DECLARE value VARCHAR(255);
DECLARE occurrences INT DEFAULT 0;
DECLARE i INT DEFAULT 0;
DECLARE splitted_value VARCHAR(255);
DECLARE done INT DEFAULT 0;
DECLARE cur CURSOR FOR SELECT tmp_table1.id, tmp_table1.value FROM
tmp_table1 WHERE tmp_table1.value IS NOT NULL AND tmp_table1.value != '';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
SET #expr = CONCAT('CREATE TEMPORARY TABLE tmp_table1 (id INT NOT NULL, value VARCHAR(255)) ENGINE=Memory SELECT ',
id_column,' id, ', value_column,' value FROM ',tablename);
PREPARE stmt FROM #expr;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
DROP TEMPORARY TABLE IF EXISTS tmp_table2;
CREATE TEMPORARY TABLE tmp_table2 (id INT NOT NULL, value VARCHAR(255) NOT NULL) ENGINE=Memory;
OPEN cur;
read_loop: LOOP
FETCH cur INTO id, value;
IF done THEN
LEAVE read_loop;
END IF;
SET occurrences = (SELECT CHAR_LENGTH(value) -
CHAR_LENGTH(REPLACE(value, delim, '')) + 1);
SET i=1;
WHILE i <= occurrences DO
SET splitted_value = (SELECT TRIM(SUBSTRING_INDEX(
SUBSTRING_INDEX(value, delim, i), delim, -1)));
INSERT INTO tmp_table2 VALUES (id, splitted_value);
SET i = i + 1;
END WHILE;
END LOOP;
SELECT * FROM tmp_table2;
CLOSE cur;
DROP TEMPORARY TABLE tmp_table1;
END; $$
delimiter ;
Usage example (normalization):
CALL split_value_into_multiple_rows('my_contacts', 'contact_id', 'interests', ',');
CREATE TABLE interests (
interest_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
interest VARCHAR(30) NOT NULL
) SELECT DISTINCT value interest FROM tmp_table2;
CREATE TABLE contact_interest (
contact_id INT NOT NULL,
interest_id INT NOT NULL,
CONSTRAINT fk_contact_interest_my_contacts_contact_id FOREIGN KEY (contact_id) REFERENCES my_contacts (contact_id),
CONSTRAINT fk_contact_interest_interests_interest_id FOREIGN KEY (interest_id) REFERENCES interests (interest_id)
) SELECT my_contacts.contact_id, interests.interest_id
FROM my_contacts, tmp_table2, interests
WHERE my_contacts.contact_id = tmp_table2.id AND interests.interest = tmp_table2.value;
CREATE PROCEDURE `getVal`()
BEGIN
declare r_len integer;
declare r_id integer;
declare r_val varchar(20);
declare i integer;
DECLARE found_row int(10);
DECLARE row CURSOR FOR select length(replace(val,"|","")),id,val from split;
create table x(id int,name varchar(20));
open row;
select FOUND_ROWS() into found_row ;
read_loop: LOOP
IF found_row = 0 THEN
LEAVE read_loop;
END IF;
set i = 1;
FETCH row INTO r_len,r_id,r_val;
label1: LOOP
IF i <= r_len THEN
insert into x values( r_id,SUBSTRING(replace(r_val,"|",""),i,1));
SET i = i + 1;
ITERATE label1;
END IF;
LEAVE label1;
END LOOP label1;
set found_row = found_row - 1;
END LOOP;
close row;
select * from x;
drop table x;
END
Here is my solution
-- Create the maximum number of words we want to pick (indexes in n)
with recursive n(i) as (
select
1 i
union all
select i+1 from n where i < 1000
)
select distinct
s.id,
s.oaddress,
-- n.i,
-- use the index to pick the nth word, the last words will always repeat. Remove the duplicates with distinct
if(instr(reverse(trim(substring_index(s.oaddress,' ',n.i))),' ') > 0,
reverse(substr(reverse(trim(substring_index(s.oaddress,' ',n.i))),1,
instr(reverse(trim(substring_index(s.oaddress,' ',n.i))),' '))),
trim(substring_index(s.oaddress,' ',n.i))) oth
from
app_schools s,
n

How to pass comma seperated values in IN where clause

I want to ask how to pass the '30','31','32' to SQL WHERE IN clause For example
EXEC SQL DECLARE abcd CURSOR FOR SELECT Consignment FROM Transaction WHERE order_type IN (:dest)
where dest will hold the value '30','31','32'.
I have tried as above example but it is not working SQL did not return any result.
There is no easy way.split the data on seperator(,), insert into a table in a while loop. Then "IN (select "column_name" from temp table)". Now split and insert into a temp table is a tricky thing.
DECLARE #StringToSeperate VARCHAR(10)
SELECT #StringToSeperate = '1,2,5'
--SELECT #StringToSeperate IDs INTO #Test
CREATE TABLE #valus (ID int)
DECLARE #CommaSeperatedValue VARCHAR(255) = ''
DECLARE #Position INT = LEN(#StringToSeperate)
--Add Each Value
WHILE CHARINDEX(',', #StringToSeperate) > 0
BEGIN
SELECT #Position = CHARINDEX(',', #StringToSeperate)
SELECT #CommaSeperatedValue = SUBSTRING(#StringToSeperate, 1, #Position-1)
INSERT INTO #valus
SELECT #CommaSeperatedValue
SELECT #StringToSeperate = SUBSTRING(#StringToSeperate, #Position+1, LEN(#StringToSeperate)-#Position)
END
--Add Last Value
IF (LEN(LTRIM(RTRIM(#StringToSeperate)))>0)
BEGIN
INSERT INTO #valus
SELECT SUBSTRING(#StringToSeperate, 1, #Position)
END
SELECT ID FROM #valus

MySQL procedure returning incorrect value to PHP

I have this stored procedure that inserts data into the event table. The problem is that the value returned to PHP in select lastNum; is 1 lower (inserted as 2 but will return 1) than when it is used in the previous insert statement. This doesn't make any sense to me as the value is not changed in between the 2 lines.
DROP PROCEDURE IF EXISTS `insertEvent`$$
CREATE DEFINER=`root`#`localhost` PROCEDURE `insertEvent`(ptitle varchar(500), pdescription varchar(500), pxcoord int(4), pycoord int(4), ptype char(1), pnumber int(11))
begin
declare numExists int(1);
declare lastNum int(9);
select count(*) from event where `number`=pnumber;
select insAndIncEventId() into lastNum from dual;
if numExists > 0 then
update event set `number`=`number`+1 where `number`>=pnumber;
end if;
insert into event (id, title, description, xcoord, ycoord, `type`, `number`) values (lastNum, ptitle, pdescription, pxcoord, pycoord, ptype, pnumber);
select lastNum;
end$$
drop function if exists `insAndIncEventId`$$
create function `insAndIncEventId`() returns int(9)
begin
declare event_id int(9);
select nextId into event_id from eventid;
update eventid set nextid=nextid+1;
return event_id;
end$$
The PHP is as follows:
$eventid=$eventidstmt->fetch(PDO::FETCH_BOTH);
fb("event id count from sql:".count($eventid));
fb("event id from sql:".$eventid[0]);

Stored procedure works on local but won't execute on server

I wrote a stored procedure that worked in my local machine but in the server, it wont execute! It would be great to have help
The stored procedure is
DROP PROCEDURE `ASKUS_INSERT`//
CREATE DEFINER=`root`#`localhost` PROCEDURE `ASKUS_INSERT`(
SENDERCONSUMERID INT(11),
QUESTION_POSTED TEXT,
DESCRIPTION_POSTED TEXT,
NETWORK_ID INT(11),
COMMTYPEID INT(11),
CONSUMERID INT(11),
CATEGORY_ID INT(11),
ACTIONID INT(11),
QUESTION_SLUG TEXT
)
BEGIN
DECLARE LASTINSERTEDID INT DEFAULT 0;
DECLARE GETTIPSAMOUNT INT DEFAULT 0;
DECLARE GETTIPSAMOUNTCONSUMER INT DEFAULT 0;
DECLARE SETTIPSAMOUNTCONSUMER INT DEFAULT 0;
DECLARE CHECKCOUNTTIPSEXIST INT DEFAULT 0;
SELECT COUNT(*) INTO CHECKCOUNTTIPSEXIST FROM ACTION_ENTERPRISE_MAPPING WHERE ACTION_ID = ACTIONID;
IF CHECKCOUNTTIPSEXIST > 0 THEN
SELECT SUM(TIP_AMOUNT) INTO GETTIPSAMOUNT FROM ACTION_ENTERPRISE_MAPPING WHERE ACTION_ID = ACTIONID;
ELSE
SET GETTIPSAMOUNT = 0;
END IF;
SELECT CONSUMER_TIPS INTO GETTIPSAMOUNTCONSUMER FROM CONSUMER_PROFILE WHERE CONSUMER_ID = SENDERCONSUMERID;
SET SETTIPSAMOUNTCONSUMER = GETTIPSAMOUNTCONSUMER + GETTIPSAMOUNT;
INSERT INTO NETWORK_COMMUNICATIONS (COMMUNICATIONS_ID,SENDER_CONSUMER_ID,NETWORK_COMM_TYPE_ID,PARENT_COMMUNICATIONS_ID,IS_ACTIVE,LAST_MOD_TIME,CONSUMER_ID) VALUES ('',SENDERCONSUMERID,COMMTYPEID,'0','1',NOW(),CONSUMERID);
SET LASTINSERTEDID = LAST_INSERT_ID();
UPDATE CONSUMER_PROFILE SET CONSUMER_TIPS = SETTIPSAMOUNTCONSUMER WHERE CONSUMER_ID = SENDERCONSUMERID;
INSERT INTO CONSUMER_ACTION_LOG (ACTION_LOG_ID,ACTION_ID,CONSUMER_ID,TIPS_AMOUNT,LAST_MOD_TIME,COMMUNICATIONS_ID,COMM_TYPE_ID) VALUES ('',ACTIONID,SENDERCONSUMERID,GETTIPSAMOUNT,NOW(),LASTINSERTEDID,ACTIONID);
INSERT INTO NETWORK_COMMUNICATIONS_MESSAGE (NETWORK_COMMUNICATION_MESSAGE_ID,COMMUNICATIONS_ID,SUBJECT,MESSAGE,IS_ACTIVE,LAST_MOD_TIME,QUESTION_SLUG) VALUES ('',LASTINSERTEDID,QUESTION_POSTED,DESCRIPTION_POSTED,'1',NOW(),QUESTION_SLUG);
INSERT INTO COMMUNICATION_INTEREST_MAPPING (ID,CONSUMER_INTEREST_EXPERT_ID,CONSUMER_ID,COMMUNICATION_ID,IN_NETWORK,LAST_MOD_TIME) VALUES ('',CATEGORY_ID,SENDERCONSUMERID,LASTINSERTEDID,NETWORK_ID,NOW());
IF SENDERCONSUMERID != 0 AND CONSUMERID != 0 AND SENDERCONSUMERID != CONSUMERID THEN
INSERT INTO CONSUMER_NOTIFICATION (CONSUMER_NOTIFICATION_ID,CONSUMER_ID,SENDER_CONSUMER_ID,ACTION_ID,COMMUNICATIONS_ID,IS_ACTIVE,LAST_MOD_TIME) VALUES ('',CONSUMERID,SENDERCONSUMERID,COMMTYPEID,LASTINSERTEDID,'1',NOW());
END IF;
END
It says there are many syntax errors and also unknown variables. In that case it should not work in my localhost. But it did! Im confused!
Shouldn't you change the delimiter if this is to work? Now you have ; halfway that may be causing trouble?
You can check out this manual page for an example that looks like this:
mysql> delimiter //
mysql> CREATE PROCEDURE simpleproc (OUT param1 INT)
-> BEGIN
-> SELECT COUNT(*) INTO param1 FROM t;
-> END//
Query OK, 0 rows affected (0.00 sec)
mysql> delimiter ;
As you can see, the delimiter is set to "//" first. Your first line implies that you are trying to do something like that anyway. Maybe you just forgot to paste the delimiter lines?
this:
DROP PROCEDURE `ASKUS_INSERT`//
would only work with the delimiter set at '//'. You should (see example) probably end with // as well.

split keywords for post php mysql

i have one table store post id and it's tags like :
Post_id | Tags
--------------------------------------
1 | keyword1,keyword2,keyword3
I want to loop though each row at this table and do :
put the keyword1,keyword2,keyword3 in new table :
word_id | word_value
-------------------------
1 | keyword1
2 | keyword2
3 | keyword3
get mysql_insert_id() foreach (or exist word_id if word_value already there) and then put in the new table like :
post_id | word_id
------------------
1 | 1
1 | 2
1 | 3
I've using php and mysql for do that task but this is slowly. Anyone have good idea?
do something like this:
-- TABLES
drop table if exists post_tags;
create table post_tags
(
post_id int unsigned not null auto_increment primary key,
tags_csv varchar(1024) not null
)
engine=innodb;
drop table if exists keywords;
create table keywords
(
keyword_id mediumint unsigned not null auto_increment primary key,
name varchar(255) unique not null
)
engine=innodb;
-- optimised for queries such as - select all posts that have keyword 3
drop table if exists post_keywords;
create table post_keywords
(
keyword_id mediumint unsigned not null,
post_id int unsigned not null,
primary key (keyword_id, post_id), -- clustered composite PK !
key (post_id)
)
engine=innodb;
-- STORED PROCEDURES
drop procedure if exists normalise_post_tags;
delimiter #
create procedure normalise_post_tags()
proc_main:begin
declare v_cursor_done tinyint unsigned default 0;
-- watch out for variable names that have the same names as fields !!
declare v_post_id int unsigned;
declare v_tags_csv varchar(1024);
declare v_keyword varchar(255);
declare v_keyword_id mediumint unsigned;
declare v_tags_done tinyint unsigned;
declare v_tags_idx int unsigned;
declare v_cursor cursor for select post_id, tags_csv from post_tags order by post_id;
declare continue handler for not found set v_cursor_done = 1;
set autocommit = 0;
open v_cursor;
repeat
fetch v_cursor into v_post_id, v_tags_csv;
-- split the out the v_tags_csv and insert
set v_tags_done = 0;
set v_tags_idx = 1;
while not v_tags_done do
set v_keyword = substring(v_tags_csv, v_tags_idx,
if(locate(',', v_tags_csv, v_tags_idx) > 0,
locate(',', v_tags_csv, v_tags_idx) - v_tags_idx,
length(v_tags_csv)));
if length(v_keyword) > 0 then
set v_tags_idx = v_tags_idx + length(v_keyword) + 1;
set v_keyword = trim(v_keyword);
-- add the keyword if it doesnt already exist
insert ignore into keywords (name) values (v_keyword);
select keyword_id into v_keyword_id from keywords where name = v_keyword;
-- add the post_keywords
insert ignore into post_keywords (keyword_id, post_id) values (v_keyword_id, v_post_id);
else
set v_tags_done = 1;
end if;
end while;
until v_cursor_done end repeat;
close v_cursor;
commit;
end proc_main #
delimiter ;
-- TEST DATA
insert into post_tags (tags_csv) values
('keyword1,keyword2,keyword3'),
('keyword1,keyword5'),
('keyword4,keyword3,keyword6,keyword1');
-- TESTING
call normalise_post_tags();
select * from post_tags order by post_id;
select * from keywords order by keyword_id;
select * from post_keywords order by keyword_id, post_id;
for each keyword, do
insert into newtable (id, keyword) select id, 'aKeyword' from oldtable where oldtable.keywords like '%aKeyword%'
if oldtable.keywords is just a VARCHAR, or
insert into newtable (id, keyword) select id, 'aKeyword' from oldtable where FIND_IN_SET('aKeyword',keywords)>0
if it's a SET type.

Resources