SQL Server : create a column by summing another column - sql

I am trying to create a new column in my table by summing up values from another column within the same table
Here is an example:
Header 1 Header 2 Header 3 (new column)
------------------------------------------------------
1 1 1 1
2 2 6 12
3 2 6 12
4 3 4 8
5 3 4 8
I want the sum to be done categorically based on the categories in Header 2, with the values of Header 3.
What SQL code can I use for this?

You need window function :
select t.*, sum(header3) over (partition by header2) as newcol
from table t;

You can also use cte structure like:
;with cte (header2,Total) as (
select header2,sum(header3) as Total
from table
group by header2
)
select t.*,cte.Total
from table t
inner join cte on cte.header2 = t.header2

You can also use
SELECT T1.*,
(SELECT SUM(Header3) FROM T WHERE Header2 = T1.Header2) ExpectedResults
FROM T T1;

Related

Row Number with specific window size

I want to group records by row numbers.
Like from row 1-3 in group 1 , 4-6 in group 2 , 7-9 in group 3 and so on.
Suppose below is the table structure:
Row NumberDataValue
1 A 10
2 A 5
3 A 1
4 A 33
5 A 2
6 A 127
1 B 1
2 B 0
3 B 7
4 B 7
5 B 5
6 B 8
7 B 1
8 B 0
I want a output like this:
GroupValue
1 10
1 5
1 1
2 33
2 2
2 127
1 1
1 0
1 7
2 7
2 5
2 8
3 1
3 0
I am using Oracle 11G.
I can achieve this using PL/SQL. But I have to use SQL only. As I have to use this query in a reporting tool.
If this is a duplicate question please provide the link of the answered question.
Subtract 1 from the column "RowNumber" and divide by 3.
Then use TRUNC() to get the integer part:
SELECT TRUNC(("RowNumber" - 1) / 3) + 1 "Group",
"Value"
FROM tablename
See the demo.
I would assume the name of the first column is ordering.
You can do:
select
1 + trunc(row_number() over(partition by data order by ordering) - 1) / 3,
value
from t
What you show looks like the output from something like this:
select ceil(rn/3) as grp, value
from your_table
order by rn;
Note that "row number" and "group" are reserved words/phrases which should not be used as column names. I used rn and grp instead.
I think the ceiling function is the simplest way to arrive at what you want. If you want to base it on the RowNumber column:
select ceil( RowNumber / 3.0) as grouping
If you want to calculate it yourself using row_number():
select ceil( row_number() over (order by RowNumber) / 3.0 ) as grouping

SQL: Selecting rows from non unique column values once partitioned by another column

Using SQL here. Trying to select all rows where the column value is unique within that specific partition.
Have tried:
select *
from dataTable
where value in ( select value
from dataTable
group by tv_id, value
having count(*) > 1)
but it returns the full table-- i think the issue is that the values for many of tv_ids are identical and overlap.
What I have:
tv_id value
1 1
1 2
1 2
1 3
2 1
2 1
2 2
2 3
2 4
3 1
3 1
3 2
What I want:
tv_id value
1 2
1 2
2 1
2 1
3 1
3 1
I have a bunch of tv_ids and essentially, I only want the rows where the value is not unique within each tv_id.
Ex: I don't want tv_id, value: 3, 2 because it is the only combination in the data.
Thanks in advance!
Maybe something like this does the trick
Oracle Option
I include this oracle version because it enables you to understand better what are you querying.
select tv_id, value
from dataTable
where (tv_id, value) in (
select tv_id, value
from dataTable
group by tv_id, value
having count(1) > 1
)
SQL
But this is a standard sql version that will work with almost any database engine
select tv_id, value
from dataTable d1
join (
select tv_id, value
from dataTable
group by tv_id, value
having count(1) > 1
) d2
on d1.tv_id=d2.tv_id
and d1.value=d2.value
You need to query the same table twice because the group by makes a distinct in your data, so you won't retrieve duplicated rows as you show in your expected output.

Is there a way to update groups of rows with separate incrementing values in one query

Lets say you have the following table:
Id Index
1 3
1 1
2 1
3 3
1 5
what I would like to have is the following:
Id Index
1 0
1 1
2 0
3 0
1 2
As you might notice, the goal is for every row where Id is the same, to incrementally update the Index column, starting from zero.
Now, I know this is fairly simple with using cursors, but out of curiosity is there a way to do this with single UPDATE query, somehow combining with temp tables, common table expressions or something similar?
Yes, assuming that the you don't really care about the order of the values for the new index values. SQL Server offers updatable CTEs and window functions that do exactly what you want:
with toupdate as (
select t.*, row_number() over (partition by id order by (select NULL)) as newindex
from table t
)
update toupdate
set index = newindex;
If you want them in a specific order, then you need another column to specify the ordering. The existing index column doesn't work.
With Row_number() -1 and CTE you can write as:
CREATE TABLE #temp1(
Id int,
[Index] int)
INSERT INTO #temp1 VALUES (1,3),(1,1),(2,1),(3,3),(1,5);
--select * from #temp1;
With CTE as
(
select t.*, row_number() over (partition by id order by (select null))-1 as newindex
from #temp1 t
)
Update CTE
set [Index] = newindex;
select * from #temp1;
Demo
I'm not sure why you would want to do this really, but I had fun figuring it out!
This solution relies on your table having a primary key for the self join... but you could always create an auto inc index if none exists and this is a one off job... This will also have the added benefit of getting you to think about the precise ordering of this you want... as currently there is no way of saying which order [ID] will get [Index] in.
UPDATE dbo.Example
SET [Index] = b.newIndex
FROM dbo.Example a
INNER JOIN (
select
z.ID,
z.[Index],
(row_number() over (partition by ID order by (select NULL))) as newIndex
from Example z
) b ON a.ID = b.ID AND a.[Index]=b.[Index] --Is this a unique self join for your table?.. no PK provided. You might need to make an index first.
Probably, this is what you want
SELECT *,RANK() OVER(PARTITION BY Id ORDER BY [Index])-1 AS NewIndex FROM
(
SELECT 1 AS Id,3 [Index]
UNION
SELECT 1,1
UNION
SELECT 2,1
UNION
SELECT 3,3
UNION
SELECT 1,5
) AS T
& the result will come as
Now if you want to update the table then execute this script
UPDATE tblname SET Index=RANK() OVER(PARTITION BY t.Id ORDER BY t.[Index])-1
FROM tblname AS t
In case I am missing something or any further assistance is required please let me know.
CREATE TABLE #temp1(
Id int,
Value int)
INSERT INTO #temp1 VALUES (1,2),(1,3),(2,3),(4,5)
SELECT
Id
,Value
,ROW_NUMBER() OVER (PARTITION BY Id ORDER BY Id) Id
FROM #temp1
Start with this :)
Gave me results like
Id Value Count
1 2 1
1 3 2
1 2 3
1 3 4
1 2 5
1 3 6
1 2 7
1 3 8
2 3 1
2 4 2
2 5 3
2 3 4
2 4 5
2 5 6
2 4 7
2 5 8
2 3 9
2 3 10
3 4 1
4 5 1
4 5 2
4 5 3
4 5 4

SQL - Add value with previous row only

I have a table named myvals with the following fields:
ID number
-- -------
1 7
2 3
3 4
4 0
5 9
Starting on 2nd row, I would like to add the number with the previous row number. So, my end result would look like this
ID number
-- ------
1 7
2 10
3 7
4 4
5 9
You could use the LAG analytic function
SELECT Id, number + LAG(number,1,0) OVER (ORDER BY Id) FROM table
First thing's first. You can't add to null to ID 1 must have a value.
create table #temp
(
month_type datetime,
value int
)
insert into #temp
Select '2015/01/01',1
union
Select '2015/02/01',2
union
Select '2015/03/01',3
union
Select '2015/04/01',4
SELECT t.value,t1.value,(t.value+t1.value)/2 FROM #temp t1
left join #temp t on t.month_type=Dateadd(MONTH,-1,t1.month_type)

Get rows with single values using SQlite

By using SQlite, I'd like to get all rows that show in a specific column only one single distinct value. Like from following table:
A B
1 2
2 1
3 2
4 3
5 1
6 1
7 2
8 4
9 2
Here I'd like to get only row Nr. 4 an 8 as there values (3 and 4) occur only once in the entire column.
You could use a query like this:
SELECT *
FROM mytable
WHERE B IN (SELECT B FROM mytable GROUP BY B HAVING COUNT(DISTINCT A)=1)
Please see fiddle here.
Subquery will return all B values that are present only once (you could also use HAVING COUNT(*)=1 in this case), the outer query will return all rows where B is returned by the subquery.