I'am findind a way to aggregate strings from differents rows into a single row in sybase ASE 15. Like this:
id | Name Result: id | Names
-- - ---- -- - -----
1 | Matt 1 | Matt, Rocks
1 | Rocks 2 | Stylus
2 | Stylus
Something like FOR XML PATH in T-SQL.
Thanks!
Sybase ASE does not have any string aggregate functions like list() or group_concat(); and while there is some support for FOR XML, it does not include support for the PATH option/feature.
Assuming you could have an unknown/variable number of rows to append, your only (ASE 15) T-SQL option would be a cursor-based solution.
If you find yourself working with ASE 16 you could write a user-defined function (UDF) to accomplish the task, eg: emulate group_concat() in ASE 16
Write below query :-
select id, cursorfunc(id) from table
Then create below cursor which is used in above query
DECLARE ListCurs CURSOR FOR
//Query to fetch the name
select name from table where id=#id
OPEN ListCurs
SELECT #Status = 0
WHILE #Status = 0
BEGIN
FETCH ListCurs INTO #name
IF #Status = 0
BEGIN
SELECT #res = CASE WHEN #res IS NULL THEN '' ELSE #res + '& ' END + #name
END
END
CLOSE ListCurs
RETURN (#res)
You could try this:
select id,list(Names,',' order by id) from TableName a group by id
Related
Wasn't sure how to title the question but hopefully this makes sense :)
I have a table (OldTable) with an index and a column of comma separated lists. I'm trying to split the strings in the list column and create a new table with the indexes coupled with each of the sub strings of the string it was connected to in the old table.
Example:
OldTable
index | list
1 | 'a,b,c'
2 | 'd,e,f'
NewTable
index | letter
1 | 'a'
1 | 'b'
1 | 'c'
2 | 'd'
2 | 'e'
2 | 'f'
I have created a function that will split the string and return each sub string as a record in a 1 column table as so:
SELECT * FROM Split('a,b,c', ',', 1)
Which will result in:
Result
index | string
1 | 'a'
1 | 'b'
1 | 'c'
I was hoping that I could use this function as so:
SELECT * FROM Split((SELECT * FROM OldTable), ',')
And then use the id and string columns from OldTable in my function (by re-writing it slightly) to create NewTable. But I as far as I understand sending tables into the function doesn't work as I get: "Subquery returned more than 1 value. ... not premitted ... when the subquery is used as an expression."
One solution I was thinking of would be to run the function, as is, on all the rows of OldTable and insert the result of each call into NewTable. But I'm not sure how to iterate each row without a function. And I can't send tables into the a function to iterate so I'm back at square one.
I could do it manually but OldTable contains a few records (1000 or so) so it seems like automation would be preferable.
Is there a way to either:
Iterate over OldTable row by row, run the row through Split(), add the result to NewTable for all rows in OldTable. Either by a function or through regular sql-transactions
Re-write Split() to take a table variable after all
Get rid of the function altogether and just do it in sql transactions?
I'd prefer to not use procedures (don't know if there is a solutions with them either) mostly because I don't want the functionality inside of the DB to be exposed to the outside. If, however that is the "best"/only way to go I'll have to consider it. I'm quite (read very) new to SQL so it might be a needless worry.
Here is my Split() function if it is needed:
CREATE FUNCTION Split (
#string nvarchar(4000),
#delimitor nvarchar(10),
#indexint = 0
)
RETURNS #splitTable TABLE (id int, string nvarchar(4000) NOT NULL) AS
BEGIN
DECLARE #startOfSubString smallint;
DECLARE #endOfSubString smallint;
SET #startOfSubString = 1;
SET #endOfSubString = CHARINDEX(#delimitor, #string, #startOfSubString);
IF (#endOfSubString <> 0)
WHILE #endOfSubString > 0
BEGIN
INSERT INTO #splitTable
SELECT #index, SUBSTRING(#string, #startOfSubString, #endOfSubString - #startOfSubString);
SET #startOfSubString = #endOfSubString+1;
SET #endOfSubString = CHARINDEX(#delimitor, #string, #startOfSubString);
END;
INSERT INTO #splitTable
SELECT #index, SUBSTRING(#string, #startOfSubString, LEN(#string)-#startOfSubString+1);
RETURN;
END
Hope my problem and attempt was explained and possible to understand.
You are looking for cross apply:
SELECT t.index, s.item
FROM OldTable t CROSS APPLY
(dbo.split(t.list, ',')) s(item);
Inserting in the new table just requires an insert or select into clause.
I must create an SQL table with 90+ fields, the majority of them are bit fields like N01, N02, N03 ... N89, N90 is there a fast way of creating multiple fileds or is it possible to have one single field to contain an array of values true/false? I need a solution that can also easily be queried.
There is no easy way to do this and it will be very challenging to do queries against such a table. Create a table with three columns - item number, bit field number and a value field. Then you will be able to write 'good' succinct Tsql queries against the table.
At least you can generate ALTER TABLE scripts for bit fields, and then run those scripts.
DECLARE #COUNTER INT = 1
WHILE #COUNTER < 10
BEGIN
PRINT 'ALTER TABLE table_name ADD N' + RIGHT('00' + CONVERT(NVARCHAR(4), #COUNTER), 2) + ' bit'
SET #COUNTER += 1
END
TLDR: Use binary arithmetic.
For a structure like this
==============
Table_Original
==============
Id | N01| N02 |...
I would recommend an alternate table structure like this
==============
Table_Alternate
==============
Id | One_Col
This One_Col is of varchar type which will have value set as
cast(n01 as nvarchar(1)) + cast(n02 as nvarchar(1))+ cast(n03 as nvarchar(1)) as One_Col
I however feel that you'd use C# or some other programming language to set value into column. You can also use bit and bit-shift operations.
Whenever you need to get a value, you can use SQL or C# syntax(treating as string)
In sql query terms you can use a query like
SELECT SUBSTRING(one_col,#pos,1)
and #pos can be set like
DECLARE #Colname nvarchar(4)
SET #colname=N'N32'
-- ....
SET #pos= CAST(REPLACE(#colname,'N','') as INT)
Also you can use binary arithmetic too with ease in any programming language.
Use three columns.
Table
ID NUMBER,
FIELD_NAME VARCHAR2(10),
VALUE NUMBER(1)
Example
ID FIELD VALUE
1 N01 1
1 N02 0
.
1 N90 1
.
2 N01 0
2 N02 1
.
2 N90 1
.
You can also OR an entire column for a fieldname (or fieldnameS):
select DECODE(SUM(VALUE), 0, 0, 1) from table where field_name = 'N01';
And even perform an AND
select EXP(SUM(LN(VALUE))) from table where field_name = 'N01';
(see http://viralpatel.net/blogs/row-data-multiplication-in-oracle/)
how to build a Comma seperated list from a table in SQL CE ?
I have table named Group and it has two columns ID and Name
I want to select a one comma seperated string from Group table.
So IF I have 3 records as follows in group table
ID | Name
1 | Msh
2 | Nsh
3 | Lsh
I want to get a one comma seperated list of all three names like this Msh,Nsh,Lsh
How can I get this done is SQL CE ?
Try this..
DECLARE #COMMA VARCHAR(MAX)
SET #COMMA =''
SELECT #COMMA =#COMMA +name+',' FROM yourtablename
SELECT SUBSTRING(#COMMA,0,LEN(#COMMA))
You can develop a simple logic in SQL. This is a dummy code you can try and modify the code as per your requirements.
declare
i varchar2(100);
j varchar2(100);
begin
for i in (select name from avrajit)
loop
j:=i.name||','||j;
end loop;
dbms_output.put_line(j);
end;
---------------------------------------
OUTPUT
---------------------------------------
Hitesh,Sushil2,Mukul,Shyam,Nikheel,Avrajit,Sushil,
Statement processed.
I have a table with hundreds of columns. I need to take the result of every column (except one) and put them into an array and bring back the rest of the results. Here it was the table looks like:
ID x123 x124 x125 x126 ......
2323343 0 0 0 1
3434566 1 1 1 0
3434342 1 1 0 0
3366577 0 1 1 1
.... .... .... .... ....
This table continues on for a while. Basically I need all of the x# column's results brought back in an array with the rest of the tables results (except for the ID column). So that my results would look like:
array x123 x124 x125 x126 ......
{0,0,0,1,...} 0 0 0 1
{1,1,1,0,...} 1 1 1 0
{1,1,0,0,...} 1 1 0 0
{0,1,1,1,...} 0 1 1 1
.... .... .... .... ....
my current SQL statement is something like this:
select * from mffcu.crosstab_183
I figure this would take a function of some sort to build a table with these results and that is fine. I really don't know where to begin with getting EVERY column and EVERY record to be thrown into an array right now without NAMING every single column (there are so many). Any swing in the right direction would help greatfully.
If the format of your table is as simple and strict as it seems (the first column consists of 7 digits), you could resort to a very simple trick:
SELECT string_to_array(right(left(t::text, -1), -9), ',')
FROM mffcu.crosstab_183 t;
That's all.
left() and right() require PostgreSQL 9.1 or above.
For older versions:
SELECT string_to_array(substring(rtrim(t::text, ')'), 10), ',')
FROM mffcu.crosstab_183 t;
Explain
Every type can be cast to text in Postgres, that includes composite and row types. So
Cast the whole row to text.
Remove enclosing parentheses and the first column - in this case identified by length.
Convert the result to an array with string_to_array().
I think you'll need to select all, as you are, then set the first field in each row of the result array to be an array of the remaining results in that row. It's not pretty but it works.
To my knowledge there is no way of excluding a column from a select statement. You either need to SELECT * or name each column to include.
How this is done depends on the programming language you're using to process the data returned from the SELECT.
I would recommend to look at temp tables, shema info and run-time sql
the code below may give you some ideas... (the code is done in sql server dialect. some adjustments might be necessery for postgree..)
CREATE TABLE #Result(Id int, ColumnId VARCHAR(10), Value TINYINT);
DECLARE db_cursor CURSOR FOR
SELECT 'INSERT INTO #Result SELECT ID, ''' + COLUMN_NAME +''', '+ COLUMN_NAME + ' FROM ManyColumnsTable' --'
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = N'ManyColumnsTable' AND COLUMN_NAME LIKE 'x%'
DECLARE #command NVARCHAR(80)
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO #command
WHILE ##FETCH_STATUS = 0
BEGIN
PRINT #command
EXECUTE sp_executesql #command
FETCH NEXT FROM db_cursor INTO #command
END
CLOSE db_cursor
DEALLOCATE db_cursor
SELECT * FROM #Result --WHERE ColumnId = 'x102'
DROP TABLE #Result
We have .mdb file with hundreds of tables: Lesson1, Lesson2, Lesson3, Lesson4, etc. All tables have the same structure:
Lesson<n>
----------------
slide_id
name
description
status
created_date
created_by
updated_date
updated_by
What SQL statement would generate a result like this:
| table_name | slide_id | name |
|-----------------------|-------------------------------|
| Lesson1 | 1 | name for slide 1 of lesson 1 |
| Lesson1 | 2 | name for slide 2 of lesson 1 |
| Lesson2 | 1 | name for slide 1 of lesson 2 |
| Lesson2 | 2 | whatever |
| Lesson2 | 3 | again whatever |
etc.
So there are a few points here:
table names must be included
there are hundreds of tables
If the table names are known, you can create a query like:
SELECT 'Lesson1' AS table_name, slide_id, name, ... FROM Lesson1
UNION ALL SELECT 'Lesson2', slide_id, name, ... FROM Lesson2
UNION ALL SELECT 'Lesson3', slide_id, name, ... FROM Lesson3
UNION ALL SELECT 'Lesson4', slide_id, name, ... FROM Lesson4
UNION ALL SELECT 'Lesson5', slide_id, name, ... FROM Lesson5
Cursors are only needed if the number of tables is in constant flux. If not, this should do the trick.
Hint: to generate the initial query, paste the names of the table in Excel, and use a formula in the next cell over to create that table's "UNION ALL" statement. Then copy and paste straight back into Access. (Or create it dynamically using a cursor, but copy/paste and a quick formula is easy, and you can save the excel file just in case you need to add tables in bulk, change the columns selected, etc.)
And, obviously, the end solution should be to consolidate the tables, if possible, and add a discriminator field when querying. Heck, if you have to, it's easier to maintain hundreds of queries that each pull one lesson's rows (again, Excel can be a handy batch-update tool), than hundreds of lessons tables that must have identical structures.
Using sql server, I can unfortunately see this only done with a CURSOR X-(.
This should help
DECLARE #Name VARCHAR(50)
DECLARE Cur CURSOR FOR
SELECT name
FROM sysobjects
WHERE xtype = 'U'
and name like 'Lesson%'
OPEN Cur
FETCH NEXT FROM Cur INTO #Name
DECLARE #RetTable TABLE(
TableName VARCHAR(50),
slide_id INT,
name VARCHAR(100)
)
WHILE ##FETCH_STATUS = 0
BEGIN
INSERT INTO #RetTable EXEC ('SELECT ''' + #Name + ''',slide_id , Name FROM ' + #Name)
FETCH NEXT FROM Cur INTO #Name
END
CLOSE Cur
DEALLOCATE Cur
SELECT *
FROm #RetTable
OK, then if you can use a macro/vba code you can create a temp table called AllLessons and run the following code. I tested this from a form with a button.
Private Sub Command0_Click()
Dim iTable As Integer
For iTable = 0 To CurrentDb.TableDefs.Count - 1
Dim tableName As String
tableName = CurrentDb.TableDefs(iTable).Name
If (Left(tableName, Len("Lesson")) = "Lesson") Then
CurrentDb.Execute "INSERT INTO AllLessons ([table_name],[slide_id],[name]) SELECT """ & tableName & """, [slide_id],[name] FROM " & tableName
End If
Next iTable
End Sub