Concatenate field data with previous and next rows - tsql

I want to concatenate a field with previous and next rows. for example if I have this:
|ID|word|
|0 |Hi! |
|1 |How |
|2 |Are |
|3 |You |
I want to create a stored procedure with to input, 'before' and 'after' which indicate how many rows should use for previous and next of current row.
for example if we have before=1 and after=1 then we'll get this
|ID|word |
|0 |Hi! How |
|1 |Hi! How Are|
|2 |How Are You|
|3 |Are You |
and if we have before=2 and after=1 then we'll get this
|ID|word |
|0 |Hi! How |
|1 |Hi! How Are |
|2 |Hi! How Are You|
|3 |How Are You |
Thanks in advance

Check this:
DECLARE #before TINYINT = 2
DECLARE #after TINYINT = 1
SELECT ISNULL(( SELECT STUFF((SELECT ISNULL(TblBefore.word, '') + ' '
FROM Tbl TblBefore
WHERE TblBefore.Id BETWEEN T.Id - #before AND T.Id
- 1
FOR XML PATH('') ,
TYPE).value('.', 'varchar(max)'), 1, 0, '') AS ChildValues
), '') + T.Word + ' '
+ ISNULL(( SELECT STUFF((SELECT ISNULL(TblBefore.word, '') + ' '
FROM Tbl TblBefore
WHERE TblBefore.Id BETWEEN T.Id + 1 AND T.Id
+ #after
FOR XML PATH('') ,
TYPE).value('.', 'varchar(max)'), 1, 0,
'') AS ChildValues
), '')
FROM Tbl T

SELECT Columnname + ' ' + (
SELECT TOP 1 Myt2.Columnname
FROM table1 Myt2
WHERE Myt2.ColumnID < t1.ColumnID
ORDER BY
ColumnID
)
FROM table1 Myt1
ORDER BY
Myt1.ColumnID
This code snippet works for 2 levels...:) still not the complete answer. It may help to get you to nth level.

Related

Redshift Merge rows and conflict-resolve by timestamp

This is unlike the selecting row with latest timestamp question and is specific to Redshift
I want to allow users to update parts of a (staging) table row at different points in time while avoiding invoking UPDATE statements. This is done by an append-only approach where we keep adding rows where only the unique id and a timestamp is mandatory and the other columns may or may not have a value provided.
Question:
Given a table where apart from "primary key" (not truely enforced) and a timestamp column, all other columns in that table are nullable, how do I merge all rows that have the same primary key into one row by picking the most recent non-null value for each nullable columns, if one such non-null value exists.
Example:
|id|timestamp|status|stringcol|numcol|
|1 |456 |begin | | |
|1 |460 | | | 2 |
|2 |523 | | foo | |
|1 |599 |mid | blah | |
|2 |624 |begin | | |
|1 |721 |done | | 60 |
should produce
|id|timestamp|status|stringcol|numcol|
|2 |624 |begin | foo | |
|1 |721 |done | blah | 60 |
This can be achieved using Redshift's LISTAGG function combined with SPLIT_PART function.
LISTAGG concatenates all values in a group into a single string, optionally allow you to order to contatenation and provide a delimiter.
SPLIT_PART splits a string by a delimiter and returns the chosen part
Using the above example 5-column table, you would need something like this:
SELECT id,
MAX(last_updated),
SPLIT_PART(LISTAGG(status, ',') WITHIN GROUP(ORDER BY last_updated DESC), ',', 1),
SPLIT_PART(LISTAGG(stringcol, ',') WITHIN GROUP(ORDER BY last_updated DESC), ',', 1),
SPLIT_PART(LISTAGG(numcol, ',') WITHIN GROUP(ORDER BY last_updated DESC), ',', 1)
FROM table
GROUP BY 1;

Any (array) comparison does not work

I had a table1 (id - unique)
|---|----------|
|id | array |
|---|----------|
|0 | [2, 4, 6]|
|1 | [3, 5, 1]|
|---|----------|
and table2
|---|----|
|id |val |
|---|----|
|1 | 23 |
|2 | 34 |
|3 | 19 |
|4 | 61 |
|5 | 47 |
|6 | 3 |
|---|----|
I don't now how to make a request like this:
SELECT val FROM table2 WHERE id = ANY(SELECT array FROM table1 WHERE id = 1)
Edit
Or simpler this does not work:
select 2 = any (select array[2, 4]);
ERROR: operator does not exist: integer = integer[]
LINE 1: select 2 = any (select array[2, 4]);
^
HINT: No operator matches the given name and argument type(s). You might need to add explicit type casts.
While this works:
select 2 = any ((select array[2, 4])::int[]);
?column?
----------
t
1)
SELECT val FROM table2
WHERE id = ANY((SELECT array FROM table1 WHERE id = 1)::int[])
2)
SELECT val FROM table2
WHERE ARRAY[id] <# (SELECT array FROM table1 WHERE id = 1)
3)
SELECT val FROM table2
WHERE id in (SELECT unnest(array) FROM table1 WHERE id = 1)
4)
SELECT val FROM table2
WHERE exists (SELECT 1 FROM table1 WHERE id = 1 and table2.id = ANY(array))
5) As you can see there are a lot of possibilities ;)

Updating multiple rows with a certain value from the same table

So, I have the next table:
time | name | ID |
12:00:00| access | 1 |
12:05:00| select | null |
12:10:00| update | null |
12:15:00| insert | null |
12:20:00| out | null |
12:30:00| access | 2 |
12:35:00| select | null |
The table is bigger (aprox 1-1,5 mil rows) and there will be ID equal to 2,3,4 etc and rows between.
The following should be the result:
time | name | ID |
12:00:00| access | 1 |
12:05:00| select | 1 |
12:10:00| update | 1 |
12:15:00| insert | 1 |
12:20:00| out | 1 |
12:30:00| access | 2 |
12:35:00| select | 2 |
What is the most simple method to update the rows without making the log full? Like, one ID at a time.
You can do it with a sub query:
UPDATE YourTable t
SET t.ID = (SELECT TOP 1 s.ID
FROM YourTable s
WHERE s.time < t.time AND s.name = 'access'
ORDER BY s.time DESC)
WHERE t.name <> 'access'
Index on (ID,time,name) will help.
You can do it using CTE as below:
;WITH myCTE
AS ( SELECT time
, name
, ROW_NUMBER() OVER ( PARTITION BY name ORDER BY time ) AS [rank]
, ID
FROM YourTable
)
UPDATE myCTE
SET myCTE.ID = myCTE.rank
SELECT *
FROM YourTable ORDER BY ID

postgresql field concatenate with delimiter

Figure :
I'm sorry I created Google Translation
This enables the character to combine?
It "," it is separated on the column
While merging the col1 and col2 "|" To be separated
With following data
| col1 | col2 |
|----------|----------|
| aa,bb,cc | 11,22,33 |
| dd,ee,ff | 44,55,66 |
You can use PostgreSQL's string functions like below
SELECT string_agg(col1 || '|' || col2, ',') col
FROM (
SELECT unnest(regexp_split_to_array(col1, ',')) col1
,unnest(regexp_split_to_array(col2, ',')) col2
,row_number() OVER () rn
FROM table_name
) t
GROUP BY rn
to get the desired output as
| col |
|-------------------|
| aa|11,bb|22,cc|33 |
| dd|44,ee|55,ff|66 |
SqlFiddle

Sort hierarchical table CTE query

How I can sort a hierarchical table with CTE query ?
sample table :
|ID|Name |ParentID|
| 0| |-1 |
| 1|1 |0 |
| 2|2 |0 |
| 3|1-1 |1 |
| 4|1-2 |1 |
| 5|2-1 |2 |
| 6|2-2 |2 |
| 7|2-1-1 |5 |
and my favorite result is :
|ID|Name |ParentID|Level
| 0| |-1 |0
| 1|1 |0 |1
| 3|1-1 |1 |2
| 4|1-2 |1 |2
| 2|2 |0 |1
| 5|2-1 |2 |2
| 7|2-1-1 |5 |3
| 6|2-2 |2 |2
another Sample :
an other sample :
|ID|Name |ParentID|
| 0| |-1 |
| 1|Book |0 |
| 2|App |0 |
| 3|C# |1 |
| 4|VB.NET |1 |
| 5|Office |2 |
| 6|PhotoShop |2 |
| 7|Word |5 |
and my favorite result is :
|ID|Name |ParentID|Level
| 0| |-1 |0
| 1|Book |0 |1
| 3|C# |1 |2
| 4|VB.NET |1 |2
| 2|App |0 |1
| 5|Office |2 |2
| 7|Word |5 |3
| 6|PhotoShop |2 |2
The hierarchyid datatype is able to represent hierarchical data, and already has the desired sorting order. If you can't replace your ParentID column, then you can convert to it on the fly:
(Most of this script is data setup, the actual answer is quite small)
declare #t table (ID int not null,Name varchar(10) not null,ParentID int not null)
insert into #t(ID,Name,ParentID)
select 0,'' ,-1 union all
select 1,'Book' ,0 union all
select 2,'App' ,0 union all
select 3,'C#' ,1 union all
select 4,'VB.NET' ,1 union all
select 5,'Office' ,2 union all
select 6,'PhotoShop' ,2 union all
select 7,'Word' ,5
;With Sensible as (
select ID,Name,NULLIF(ParentID,-1) as ParentID
from #t
), Paths as (
select ID,CONVERT(hierarchyid,'/' + CONVERT(varchar(10),ID) + '/') as Pth
from Sensible where ParentID is null
union all
select s.ID,CONVERT(hierarchyid,p.Pth.ToString() + CONVERT(varchar(10),s.ID) + '/')
from Sensible s inner join Paths p on s.ParentID = p.ID
)
select
*
from
Sensible s
inner join
Paths p
on
s.ID = p.ID
order by p.Pth
ORDER BY Name should work as desired:
WITH CTE
AS(
SELECT parent.*, 0 AS Level
FROM #table parent
WHERE parent.ID = 0
UNION ALL
SELECT parent.*, Level+1
FROM #table parent
INNER JOIN CTE prev ON parent.ParentID = prev.ID
)
SELECT * FROM CTE
ORDER BY Name
Here's your sample data(add it next time yourself):
declare #table table(ID int,Name varchar(10),ParentID int);
insert into #table values(0,'',-1);
insert into #table values(1,'1',0);
insert into #table values(2,'2',0);
insert into #table values(3,'1-1',1);
insert into #table values(4,'1-2',1);
insert into #table values(5,'2-1',2);
insert into #table values(6,'2-2',2);
insert into #table values(7,'2-1-1',5);
Result:
ID Name ParentID Level
0 -1 0
1 1 0 1
3 1-1 1 2
4 1-2 1 2
2 2 0 1
5 2-1 2 2
7 2-1-1 5 3
6 2-2 2 2