I was trying to do column values concatenation in Netezza and found following for sql-server
Concatenating Column Values into a Comma-Separated List
It doesn't work for Netezza though.
Is there any solution?
What I have tried was
SELECT LEFT(COLUMN_NAME, LENGTH(COLUMN_NAME) - 1)
FROM (
SELECT COLUMN_NAME + ', '
FROM information_schema.columns
WHERE table_name IN ('Employee')
FOR XML PATH ('')
) c (COLUMN_NAME)
Thanks
A group_concat UDF that does what you want is provided here, and will need to be installed in the database in which you would like to use it. The provided tar file has an install script that does this for you. The installation looks something like this:
$ ./install testdb
CREATE AGGREGATE
Created uda
Done
CREATE AGGREGATE
Created uda
Done
The usage would look something like this:
TESTDB.ADMIN(ADMIN)=> select * from test_gc order by col1, col2;
COL1 | COL2
------+------
1 | A
1 | B
1 | C
2 | C
2 | D
2 | E
(6 rows)
TESTDB.ADMIN(ADMIN)=> select col1, group_concat(col2,',') from test_gc group by col1 order by col1;
COL1 | GROUP_CONCAT
------+--------------
1 | A,B,C
2 | C,D,E
(2 rows)
Related
I have one table having data like this:
ID | Fill
---------------
1 | ####
2 | ####Y
3 | ####Y245
I want to insert the above data into another table and expecting the result table to be:
ID | Fill
----------------
1 | (Space)
2 | Y
3 | Y245
That is, when i find ####, it should be replace by space (4 space char as it has 4#)
Here is how I'm trying to do this:
insert into table1
(
id
,case
when contains(substring([fill],1,4),'####') then ' '+substring([fill],5,100)
else [fill]
end
)
select
id
,convert(char(100),[col1]+[col2]+[col3]+[col4])
from
table2
However, its showing syntax error near "case". What am I doing wrong? how can i achieve the desired result?
Just use replace()
insert into destination_table (col1)
select replace(col1, '#', ' ' ) from source_table
If # occurs, it will be replaced. If not, then the original string is used.
The case is in the field list part of the INSERT statement and is therefore not valid.
You could just use a simple replace to achieve this
INSERT INTO table1 (id, fill)
select id, replace(fill, '####', ' ') from table2
I have a table which store 1 row per 1 survey.
Each survey got about 70 questions, each column present 1 question
SurveyID Q1, Q2 Q3 .....
1 Yes Good Bad ......
I want to pivot this so it reads
SurveyID Question Answer
1 Q1 Yes
1 Q2 Good
1 Q3 Bad
... ... .....
I use {cross apply} to acheive this
SELECT t.[SurveyID]
, x.question
, x.Answer
FROM tbl t
CROSS APPLY
(
select 1 as QuestionNumber, 'Q1' as Question , t.Q1 As Answer union all
select 2 as QuestionNumber, 'Q2' as Question , t.Q2 As Answer union all
select 3 as QuestionNumber, 'Q3' as Question , t.Q3 As Answer) x
This works but I dont want to do this 70 times so I have this select statement
select ORDINAL_POSITION
, COLUMN_NAME from INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = mytable
This gives me the list of column and position of column in the table.
So I hope I can somehow join 2nd statement with the 1st statement where by column name. However I am comparing content within a column and a column header here. Is it doable? Is there other way of achieving this?
Hope you can guide me please?
Thank you
Instead of Cross Apply you should use UNPIVOT for this query....
SQL Fiddle
MS SQL Server 2008 Schema Setup:
CREATE TABLE Test_Table(SurveyID INT, Q1 VARCHAR(10)
, Q2 VARCHAR(10), Q3 VARCHAR(10), Q4 VARCHAR(10))
INSERT INTO Test_Table VALUES
(1 , 'Yes', 'Good' , 'Bad', 'Bad')
,(2 , 'Bad', 'Bad' , 'Yes' , 'Good')
Query 1:
SELECT SurveyID
,Questions
,Answers
FROM Test_Table t
UNPIVOT ( Answers FOR Questions IN (Q1,Q2,Q3,Q4))up
Results:
| SurveyID | Questions | Answers |
|----------|-----------|---------|
| 1 | Q1 | Yes |
| 1 | Q2 | Good |
| 1 | Q3 | Bad |
| 1 | Q4 | Bad |
| 2 | Q1 | Bad |
| 2 | Q2 | Bad |
| 2 | Q3 | Yes |
| 2 | Q4 | Good |
If you need to perform this kind of operation to lots of similar tables that have differing numbers of columns, an UNPIVOT approach alone can be tiresome because you have to manually change the list of columns (Q1,Q2,Q3,etc) each time.
The CROSS APPLY based query in the question also suffers from similar drawbacks.
The solution to this, as you've guessed, involves using meta-information maintained by the server to tell you the list of columns you need to operate on. However, rather than requiring some kind of join as you suspect, what is needed is Dynamic SQL, that is, a SQL query that creates another SQL query on-the-fly.
This is done essentially by concatenating string (varchar) information in the SELECT part of the query, including values from columns which are available in your FROM (and join) clauses.
With Dynamic SQL (DSQL) approaches, you often use system metatables as your starting point. INFORMATION_SCHEMA exists in some SQL Server versions, but you're better off using the Object Catalog Views for this.
A prototype DSQL solution to generate the code for your CROSS APPLY approach would look something like this:
-- Create a variable to hold the created SQL code
-- First, add the static code at the start:
declare #SQL varchar(max) =
' SELECT t.[SurveyID]
, x.question
, x.Answer
FROM tbl t
CROSS APPLY
(
'
-- This syntax will add to the variable for every row in the query results; it's a little like looping over all the rows.
select #SQL +=
'select ' + cast(C.column_id as varchar)
+ ' as QuestionNumber, ''' + C.name
+ ''' as Question , t.' + C.name
+ ' As Answer union all
'
from sys.columns C
inner join sys.tables T on C.object_id=T.object_id
where T.name = 'MySurveyTable'
-- Remove final "union all", add closing bracket and alias
set #SQL = left(#SQL,len(#SQL)-10) + ') x'
print #SQL
-- To also execute (run) the dynamically-generated SQL
-- and get your desired row-based output all at the same time,
-- use the EXECUTE keyword (EXEC for short)
exec #SQL
A similar approach could be used to dynamically write SQL for the UNPIVOT approach.
this is the first-time I use this and I hope i will achieve this, I am getting mad. I am still a newbie about all this programming with SQL thing, I am trying to use pivot table to turn the source table in the desired output showed as below.
This is my source table
Here is the image, I was unable to upload it (https://i.stack.imgur.com/KDStF.jpg).
But whatever I try it returns me numbers but the varchar values I would like to, as it is shown above.
Would any of you know how to achieve it?
I am using Transact SQL in Sql Server, here is my code
SELECT [Ques1], [Ques2]
FROM
(
SELECT
D.DocumentId,
DA.QuestionId,
Q.ShortText,
DA.[Text],
Q.SectionId,
1 as [Count]
-- ShortText is literally 'Ques1' or 'Ques2'
FROM Document D
INNER JOIN DocumentAnswer DA
ON DA.DocumentId = D.DocumentId
INNER JOIN Question Q
ON Q.QuestionId = DA.QuestionId
WHERE D.DeleteDate IS NULL
) d
PIVOT
(
Max(ShortText)
FOR [Text] IN ([Ques1], [Ques2])
) p
SQL Fiddle
MS SQL Server 2008 Schema Setup:
Query 1:
DECLARE #TABLE TABLE (DocID INT, Ques VARCHAR(100), Ans VARCHAR(100))
INSERT INTO #TABLE VALUES
(1 , 'Ques1' , 'Hola'),
(1 , 'Ques2' , 'Padr'),
(2 , 'Ques1' , 'Excue'),
(2 , 'Ques2' , 'Dir')
SELECT * FROM
( -- Put your existing query here
SELECT * FROM #TABLE
) t
PIVOT (MAX(Ans)
FOR Ques
IN ([Ques1],[Ques2])
)p
Results:
| DOCID | QUES1 | QUES2 |
|-------|-------|-------|
| 1 | Hola | Padr |
| 2 | Excue | Dir |
Is it possible to do bulk replace without while loop or what is the best way
Table-1
+-------+--------+
| name | value |
+-------+--------+
| #1# | one |
| #2# | two |
| #3# | three |
+-------+--------+
Table-2 (updated: there is more than one different tokens in table2)
+-----------------------+
| col1 |
+-----------------------+
| string #1# string #2# |
| string #2# string #1# |
| string #3# string #2# |
+-----------------------+
I like to replace all token from Table-2 with Table-1's value column respectively.
Expected Result
+-------------------------+
| col1 |
+-------------------------+
| string one string two |
| string two string one |
| string three string two |
+-------------------------+
Current solution with While loop
declare #table1 table(name nvarchar(50),value nvarchar(50))
insert into #table1 values('#1#','one'),('#2#','two'),('#1#','three')
declare #table2 table(col1 nvarchar(50))
insert into #table2 values('string #1# string #2#'),('string #2# string #1#'),('string #3# string #2#')
WHILE EXISTS (SELECT 1 FROM #table2 t2 INNER JOIN #table1 t1 ON CHARINDEX(t1.name,[col1])>0)
BEGIN
UPDATE #table2
SET col1=REPLACE(col1,name,value)
FROM #table1
WHERE CHARINDEX(name,[col1])>0
END
select * from #table2
Thanks
I suppose you use Sql Server (you've tagged with tsql):
I've run this query on Sql fiddle with 2012 version, but on my PC I've tried with 2008r2 version.
You can procede in this way:
UPDATE table2
SET col1 = REPLACE(col1,
(SELECT name FROM table1 WHERE col1 LIKE '%' + table1.NAME + '%'),
(SELECT value FROM table1 WHERE col1 LIKE '%' + table1.NAME + '%'))
Sql Fiddle
If you want show only the value without UPDATE you can proceed in this way:
SELECT REPLACE(T2.col1, T1.name, T1.value)
FROM table1 T1
JOIN table2 T2
ON T2.col LIKE '%' T1.name + '%'
EDIT
After editing of question / comment my answer is not complete because on the same row can exist more one token. I'm thinking... :)
I thought: :D
IMHO: You must create a loop on your table because the presence of several tokens don't resolve with a single UPDATE statement with subquery, because as you written, the subquery return more than one value.
In Sql Server the REPLACE function change only token, so if you want change in one step two token you must nest your REPLACE function, but we have a number undefined of token in a row so we can't prevent to apply the exact number of REPLACE. An help you can have using a cursor and a dynamic SQL query build on runtime, so you can do a single UPDATE per row. If you want a guide line to use CURSOR and DYNAMIC SQL, please write me. Good night ;)
You can do bulk replacement with this simple piece of code:
update #table2
set col1= left(a.col1,6)+' ' + b.value from #table2 a
join #table1 b on b.name=substring(a.col1,8,3)
select * from #table2
Basically, it updates the column with a new field value.
I have a table which is filled with float values. I need to calculate the number of results grouped by their distribution around the mean value (Gaussian Distribution). Basically, it is calculated like this:
SELECT COUNT(*), FloatColumn - AVG(FloatColumn) - STDEV(FloatColumn)
FROM Data
GROUP BY FloatColumn - AVG(FloatColumn) - STDEV(FloatColumn)
But for obvious reasons, SQL Server gives this error: Cannot use an aggregate or a subquery in an expression used for the group by list of a GROUP BY clause.
My question is, can I somehow leave this computation to SQL Server? Or do I have to do it the old fashioned way? Retrieve all the data, and do the calculation myself?
To get the aggregate of the whole set you can use an empty OVER clause
WITH T(Result)
AS (SELECT FloatColumn - Avg(FloatColumn) OVER() - Stdev(FloatColumn) OVER ()
FROM Data)
SELECT Count(*),
Result
FROM T
GROUP BY Result
SQL Fiddle
You can perform a pre-aggregation of the data, and join back to the table.
Schema Setup:
create table data(floatcolumn float);
insert data values
(1234.56),
(134.56),
(134.56),
(234.56),
(1349),
(900);
Query 1:
SELECT COUNT(*) C, D.FloatColumn - A
FROM
(
SELECT AVG(FloatColumn) + STDEV(FloatColumn) A
FROM Data
) preagg
CROSS JOIN Data D
GROUP BY FloatColumn - A;
Results:
| C | COLUMN_1 |
--------------------------
| 2 | -1196.876067819572 |
| 1 | -1096.876067819572 |
| 1 | -431.436067819572 |
| 1 | -96.876067819572 |
| 1 | 17.563932180428 |