How to concatenate rows when using with groupby based on a pattern in Microsoft SQL Server? - sql

I have an example:
I want it to look like this:
Pretty much, there will be null cells following a value in the Amount Column. I want to concatenate the comment cells of those rows with null cells. I'm not sure how to do this. Is there a way to do this?

If there will be null cells following a value in the Amount Column (as you told in question) you can use ROW_NUMBER() to get unique number in cte and then calculating sum (order by new unique numbers) for every row (will be the same for one Amount).
And at last, using cte in FOR XML PATH().
--getting Sum as unique for every sequence (Amount and following values)
with cte AS
(
select Id,Amount,Number,sum(Amount)over(order by Number rows unbounded preceding)SumSeq,comment
from
(
select Id,Amount,comment,
row_number()over(order by Id)Number from Table
)x
)
select id,max(Amount),ConcatComments from
(
select id,SumSeq,Amount,
stuff((select Concat(',',comment)
from cte cte1 where cte1.SumSeq=cte2.SumSeq
for xml path('')),1,2,'') ConcatComments from cte cte2
)Z
group by SumSeq,id,ConcatComments

You can use the STRING_AGG function to concatenate the comments. Something like this:
Select ID, MAX(Amount) as Amount, STRING_AGG(Comment, ', ') as Comment
From [YourTable]
Group By ID;

Your data has no column specifying the ordering, but the results seem to depend on ordering. If you do have such a column, you can assign a grouping by counting the non-NULL values of amount for each id, and then aggregate. That would be:
select id, grp,
string_agg(comment, ', ') within group (order by <ordering column>) as comments
from (select t.*, count(amount) over (partition by id order by <ordering column>) as grp
from t
) t
group by id, grp;

Related

Sum columns value in a specific order

I would like to know if I can sum the values of a float(53) column in ascending order.
For example, if my column contains the values 5, 7 and 2. I'd like it to be computed as 2+5+7.
This order matters in my case as I'm summing millions of floats and it gives a different result at each execution.
I think you can get the sum using window functions and filtering:
select t.*
from (select t.*,
sum(col) over (order by col asc) as sum_col,
row_number() over (order by col desc) as seqnum
from t
) t
where seqnum = 1;
Or alternatively without a subquery:
select top (1) sum(col) over (order by col asc)
from t
order by col desc;
Note: This assumes that col has unique values. If duplicates are possible, just add the primary key as a second column in the order bys.
However, if the data can be stored using numeric/decimal, that might be a more sustainable solution.

Distinct rows in a table in sql

I have a table with multiple rows of the same member id. I need only distinct rows based on 2 unique columns
Ex: there are 100 different customers, the table has 1000 rows because every customer has multiple cities and segments assigned to him.
I need 100 distinct rows for these customers depending on a unique segment and city combination. There is no specific requirement for this combination, just the first from the table is fine.
So, currently the table is somewhat like this,
Hope this helps.
use row_number()
select * from (select *,row_number() over(partition by memberid order by sales) rn
from table_name
) a where a.rn=1
Handy sql-server top(1) with ties syntax for that
select top(1) with ties t.*
from table_name t
order by row_number() over(partition by memberid order by sales)
As you have no paticular requirement for which exactly row to select, any column will do at order by, it can be null as well
select top(1) with ties t.*
from table_name t
order by row_number() over(partition by memberid order by (select null))
The simplest way to do this is to use the ROW_NUMBER() OVER(GROUP BY...) syntax. You have no need to use an order by, since you want an arbitrary row, but only one, for each member.
Since you need only the expected data, and not the Row_Number value, make sure that you detail the fields returned, like below:
SELECT
MemberId,
city,
segment,
sales
FROM (
SELECT *
ROW_NUMBER() OVER (GROUP BY MemberId) as Seq
FROM [Status]
) src
WHERE Seq = 1

Oracle LEAD - return next matching column value

I having below data in one table.
And I want to get NEXT out data from OUT column. So used LEAD function in below query.
SELECT ROW_NUMBER,TIMESTAMP,IN,OUT,LEAD(OUT) OVER (PARTITION BY NULL ORDER BY TIMESTAMP) AS NEXT_OUT
FROM MYTABLE;
It gives data as below NEXT_OUT column.
But I need to know the matching next column value in sequential way like DESIRED columns. Please let me know how can i achieve this in Oracle LEAD FUNCTION
THANKS
Assign row number to all INs and OUTs separately, sort the results by placing them in a single column and calculate LEADs:
WITH cte AS (
SELECT t.*
, CASE WHEN "IN" IS NOT NULL THEN COUNT("IN") OVER (ORDER BY "TIMESTAMP") END AS rn1
, CASE WHEN "OUT" IS NOT NULL THEN COUNT("OUT") OVER (ORDER BY "TIMESTAMP") END AS rn2
FROM t
)
SELECT cte.*
, LEAD("OUT") OVER (ORDER BY COALESCE(rn1, rn2), rn1 NULLS LAST) AS NEXT_OUT
FROM cte
ORDER BY COALESCE(rn1, rn2), rn1 NULLS LAST
Demo on db<>fiddle
Enumerate in the "in"s and the "out"s and use that information for matching.
select tin.*, tout.out as next_out
from (select t.*,
count(in) over (order by timestamp) as seqnum_in
from t
) tin left join
(select t.*,
count(out) over (order by timestamp) as seqnum_out
from t
) tout
on tin.in is not null and
tout.out is not null and
tin.seqnum_in = tout.seqnum_out;

How can I assign unique value to each duplicate value in a column in a table

I have data in my table as below
Now I want to generate unique rank value to each duplicate value like 1,2,3,4 etc as below
How to do this in SQL Server 2016?
You seem to be looking for row_number():
select t.*,
row_number() over (partition by id, name order by deptid) as ranking
from t;
You can use DENSE_RANK as well,
select table.*,
DENSE_RANK() over (order by id, name ,deptid) as RANK
from table;

row_number() over() combined with order by

How can I add a sequential row number to a query that is using order by?
Let say I have a request in this form :
SELECT row_number() over(), data
FROM myTable
ORDER BY data
This will produce the desired result as rows are ordered by "data", but the row numbers are also ordered by data. I understand this is normal as my row number is generated before the order by, but how can I generate this row number after the order by?
I did try to use a subquery like this :
SELECT row_number() over(ORDER BY data), *
FROM
(
SELECT data
FROM myTable
ORDER BY data
) As t1
As shown here, but DB2 doesn't seem to support this syntax SELECT ..., * FROM
Thanks !
You also need to use alaias name before '*'
SELECT row_number() over(ORDER BY data), t1.*
FROM
(
SELECT data
FROM myTable
ORDER BY data
) As t1
You don't need a subquery to do this,
SELECT data , row_number() over(ORDER BY data) as rn
FROM myTable
ORDER BY data