SQL Server: Update Column with Sum of Other Columns When [closed] - sql-server

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 months ago.
Improve this question
Let's say I have the table structure as shown below. Which SQL script can I use to update the column Size2 in the table, with the sum of column Size, when the animals are equal? Platform is SQL Server.
I want to have a column Size2 that is the sum of the Size when animal names equal each other. I'm struggling to put the script below into an update statement but please see the select statement.
CREATE TABLE table1
(
Size nvarchar(50),
Animals nvarchar(250),
Part int,
Size2 nvarchar(250)
);
Size
Animals
Part
30
Pig
1
60
Tiger
1
10
Tiger
2
30
Pig
2
90
Lion
1
20
Lion
2
10
Lion
3
This is the desired output, I do not have a Size2 column in the table yet.
Size
Animals
Part
Size2
30
Pig
1
60
60
Tiger
1
70
10
Tiger
2
70
30
Pig
2
60
90
Lion
1
120
20
Lion
2
120
10
Lion
3
120
So far I have:
SELECT
Animals,
SUM(TRY_CONVERT(int, Size))
FROM
Table1
WHERE
Part IS NOT NULL
GROUP BY
Animals

For select statement, you can use PARTITION BY clause
This is select statement
SELECT Size, Animals, Part,
SUM(CAST(size as int)) OVER(PARTITION BY Animals) As total_size
FROM table1
WHERE part IS NOT NULL;
For update statement
UPDATE table1
SET table1.size2 = table2.total_size
FROM
table1
INNER JOIN
(SELECT Size, Animals, Part,
SUM(CAST(size as int)) OVER(PARTITION BY Animals) As total_size
FROM table1
WHERE part IS NOT NULL) AS table2
ON table1.size = table2.size AND
table1.animals = table2.animals AND
table1.part = table2.part;
Note: UPDATE statement above will only update size2 column where part is not null.
If you want to update all size2 column even though part is null, remove last line(table1.part = table2.part) will do

The desired result can be achieved by following SQL
SELECT t.Size, t.Animal, t.Part, t2.AnimalSum
FROM table1 t RIGHT JOIN
(SELECT Animal, Sum(convert(int,Size)) AS AnimalSum
FROM table1
group BY Animal) AS t2 ON t.Animal = t2.Animal
so the update can be easily done with an update using above query statement.

From your query, you can update with this
UPDATE t1
SET
t1.Size2 = t2.SumSize
FROM Table1 t1
INNER JOIN
(SELECT Animals, SUM(TRY_CONVERT(int,Size)) as SumSize
FROM Table1
WHERE Part IS NOT NULL
GROUP BY Animals) t2
ON t1.Animals = t2.Animals

Related

bring column name into row in sql server [duplicate]

This question already has answers here:
Unpivot with column name
(3 answers)
Closed 4 years ago.
I have a table with column column_name_1 , column_name_2 , column_name_3 and with one row values 0,0,1
column_name_1 , column_name_2 , column_name_3
--------------,----------------,---------------
0 , 0 , 1
I need output like
column_name_1 | 0
column_name_2 | 0
column_name_3 | 1
Is it possible?
I have checked for some unpivot example, thats not exactly my case.
Because I need Column name into column value and one row into column.
1.Unpivot with column name
Name, Maths, Science, English
Tilak, 90, 40, 60
Raj, 30, 20, 10
changed into
Name, Subject, Marks
Tilak, Maths, 90
Tilak, Science, 40
Tilak, English, 60
Clearly there is a view, Name column remains its position as it is.
2.SQL Query for generating matrix like output querying related table in SQL Server
Above link also have Customer Name column which is remains same as it is.
But in my case input and output, both not have any same position.
So if still it can be achievable through pivot, Pls help with the code.
Clearly UNPIVOT would be more performant, but if you need a dynamic approach without actually using dynamic SQL
Example
Select C.*
From YourTable A
Cross Apply ( values (cast((Select A.* for XML RAW) as xml))) B(XMLData)
Cross Apply (
Select Item = a.value('local-name(.)','varchar(100)')
,Value = a.value('.','varchar(max)')
From B.XMLData.nodes('/row') as C1(n)
Cross Apply C1.n.nodes('./#*') as C2(a)
Where a.value('local-name(.)','varchar(100)') not in ('Columns','ToExclude')
) C
Returns
Item Value
Column_name_1 0
column_name_2 0
column_name_3 1
You want APPLY :
SELECT tt.cols, tt.colsvalue
FROM table t CROSS APPLY
( VALUES ([column_name_1], 'column_name_1'),
([column_name_2], 'column_name_2'),
([column_name_3], 'column_name_3')
) tt (colsvalue, cols);

How to select random rows whose column sum meets the condition in Sql server

Is it possible to select random rows from a table whose particular column total (sum) should be less than my condition value ?
My table structure is like -
id | question | answerInSec
1 | Quest1 | 15
2 | Quest2 | 20
3 | Quest3 | 10
4 | Quest4 | 15
5 | Quest5 | 10
6 | Quest6 | 15
7 | Quest7 | 20
I want to get those random questions whose total sum of 'answerInSec' column is less than (nearest total) or equal to 60.
So random combination can be [1,2,3,4] OR [2,3,5,7] OR [4,5,6,7] etc.
I tried as follows but no luck
select id,question,answerinsec
from (select Question.*, sum(answerinsec) over (order by id) as CumTicketCount
from Question
) t
where cumTicketCount <= 60
ORDER BY NEWID();
I hope this one help
DECLARE #MaxAnswerInSec INT = 60
DECLARE #SumAnswerInSec INT = 0
DECLARE #RadomQuestionTable TABLE(Id INT, Question NVARCHAR(100), AnswerInSec INT)
DECLARE #tempId INT,
#tempQuestion NVARCHAR(100),
#tempAnswerInSec INT
WHILE #SumAnswerInSec <= #MaxAnswerInSec
BEGIN
SELECT TOP(1) #tempId = Id, #tempQuestion = Question, #tempAnswerInSec = AnswerInSec
FROM Question
WHERE Id NOT IN (SELECT Id FROM #RadomQuestionTable)
AND AnswerInSec + #SumAnswerInSec <= #MaxAnswerInSec
ORDER BY NEWID()
IF #tempId IS NOT NULL
BEGIN
INSERT INTO #RadomQuestionTable VALUES(#tempId, #tempQuestion, #tempAnswerInSec)
END
ELSE
BEGIN
BREAK
END
SELECT #tempId = NULL
SELECT #SumAnswerInSec = SUM(AnswerInSec) FROM #RadomQuestionTable
END
SELECT * FROM #RadomQuestionTable
OK. Try this. This might not be the fastest, but is easier to understand and implement. Moreover this is a SQL-only solution:
SELECT t1.id, t2.id, t3.id, t4.id FROM Question t1 CROSS JOIN Question t2
CROSS JOIN Question t3 CROSS JOIN Question t4
WHERE t2.id > t1.id AND t3.id > t2.id AND t4.id > t3.id
AND t1.answerInSec + t2.answerInSec + t3.answerInSec + t4.answerInSec = 60
What this basically does is to create a cross product of your Questions table with itself and then repeats this process two more times, thus creating N ^ 4 rows where N is the number of rows in your table. It then filters out duplicate rows by only those selecting the permutations where t1.id < t2.id < t3.id < t4.id. It then filters remaining rows by looking for the rows where the sum of all score fields is equal to your target value (60).
Note that this result set can become HUGE for even moderately sized tables. For example, a table with just 200 rows will generate a cross product of 200 ^ 4 = 1,600,000,000 rows (though a lot of them will be discarded by the WHERE clause). You should have your indexes in place if your table is large.
Also note that this query does not account for the permutations where less than 4 rows may add up to 60. You can easily modify it to do that by including a NULL row in your table (a row whose score field is zero).
SELECT *
FROM question
WHERE answerInSec<50
ORDER BY CHECKSUM(NEWID())

Retrieve Sorted Column Value in SQL Server

What i have:
I have a Column
ID  SerialNo
1  101
2  102
3  103
4  104
5  105
6  116
7  117
8  118
9  119
10 120
These are just the 10 dummy rows. The actual table has over 100 000 rows.
What I Want to get:
A method or formula like any sorting technique which could return me the starting and ending element of [SerialNo] Column for every sub-series. For example
Expected Result: 101-105, 115-120
The comma separation in the above result is not important, only the starting and ending elements are important.
What I have tried:
I did it by PL/SQL programming, by running a loop in which I’m getting the starting and ending elements getting stored in a TABLE.
But due to no. of rows (over 100 000) the query execution is taking around 2 minutes.
I have also searched about some sorting techniques for the SQL Server but I found nothing. Because rendering every row will take twice the time then a sorting algorithm
Assuming every sub series should contain 5 records, I got expected result using below sql. I hope this helps.
DECLARE #subSeriesRange INT=5;
CREATE TABLE #Temp(ID INT,SerialNo INT);
INSERT INTO #Temp VALUES(1,101),
(2,102),
(3,103),
(4,104),
(5,105),
(6,116),
(7,117),
(8,115),
(9,119),
(10,120);
SELECT STUFF((SELECT CONCAT(CASE ID%#subSeriesRange WHEN 1 THEN ',' ELSE '-' END,SerialNo)
FROM #Temp
WHERE ID%#subSeriesRange = 1 OR ID%#subSeriesRange=0
ORDER BY ID
FOR XML PATH('')),1,1,''
);
DROP TABLE #Temp;
Just finding the start and end of each series is quite straightforward:
declare #t table (ID int not null, SerialNo int not null)
insert into #t(ID,SerialNo) values
(1 ,101), (2 ,102), (3 ,103),
(4 ,104), (5 ,105), (6 ,116),
(7 ,117), (8 ,118), (9 ,119),
(10,120)
;With Starts as (
select t1.SerialNo,ROW_NUMBER() OVER (ORDER BY t1.SerialNo) as rn
from
#t t1
left join
#t t1_no
on t1.SerialNo = t1_no.SerialNo + 1
where t1_no.ID is null
), Ends as (
select t1.SerialNo,ROW_NUMBER() OVER (ORDER BY t1.SerialNo) as rn
from
#t t1
left join
#t t1_no
on t1.SerialNo = t1_no.SerialNo - 1
where t1_no.ID is null
)
select
s.SerialNo as StartSerial,
e.SerialNo as EndSerial
from
Starts s
inner join
Ends e
on s.rn = e.rn
The logic being that a Start is a row where there is no row that has the SerialNo one less than the current row, and an End is a row where there is no row that has the SerialNo one more than the current row.
This may still perform poorly if there is no index on the SerialNo column.
Results:
StartSerial EndSerial
----------- -----------
101 105
116 120
Which is hopefully acceptable since you didn't seem to care what the specific results look like. It's also keeping things set-based.

SQL Join one-to-many tables, selecting only most recent entries

This is my first post - so I apologise if it's in the wrong seciton!
I'm joining two tables with a one-to-many relationship using their respective ID numbers: but I only want to return the most recent record for the joined table and I'm not entirely sure where to even start!
My original code for returning everything is shown below:
SELECT table_DATES.[date-ID], *
FROM table_CORE LEFT JOIN table_DATES ON [table_CORE].[core-ID] = table_DATES.[date-ID]
WHERE table_CORE.[core-ID] Like '*'
ORDER BY [table_CORE].[core-ID], [table_DATES].[iteration];
This returns a group of records: showing every matching ID between table_CORE and table_DATES:
table_CORE date-ID iteration
1 1 1
1 1 2
1 1 3
2 2 1
2 2 2
3 3 1
4 4 1
But I need to return only the date with the maximum value in the "iteration" field as shown below
table_CORE date-ID iteration Additional data
1 1 3 MoreInfo
2 2 2 MoreInfo
3 3 1 MoreInfo
4 4 1 MoreInfo
I really don't even know where to start - obviously it's going to be a JOIN query of some sort - but I'm not sure how to get the subquery to return only the highest iteration for each item in table 2's ID field?
Hope that makes sense - I'll reword if it comes to it!
--edit--
I'm wondering how to integrate that when I'm needing all the fields from table 1 (table_CORE in this case) and all the fields from table2 (table_DATES) joined as well?
Both tables have additional fields that will need to be merged.
I'm pretty sure I can just add the fields into the "SELECT" and "GROUP BY" clauses, but there are around 40 fields altogether (and typing all of them will be tedious!)
Try using the MAX aggregate function like this with a GROUP BY clause.
SELECT
[ID1],
[ID2],
MAX([iteration])
FROM
table_CORE
LEFT JOIN table_DATES
ON [table_CORE].[core-ID] = table_DATES.[date-ID]
WHERE
table_CORE.[core-ID] Like '*' --LIKE '%something%' ??
GROUP BY
[ID1],
[ID2]
Your example field names don't match your sample query so I'm guessing a little bit.
Just to make sure that I have everything you’re asking for right, I am going to restate some of your question and then answer it.
Your source tables look like this:
table_core:
table_dates:
And your outputs are like this:
Current:
Desired:
In order to make that happen all you need to do is use a subquery (or a CTE) as a “cross-reference” table. (I used temp tables to recreate your data example and _ in place of the - in your column names).
--Loading the example data
create table #table_core
(
core_id int not null
)
create table #table_dates
(
date_id int not null
, iteration int not null
, additional_data varchar(25) null
)
insert into #table_core values (1), (2), (3), (4)
insert into #table_dates values (1,1, 'More Info 1'),(1,2, 'More Info 2'),(1,3, 'More Info 3'),(2,1, 'More Info 4'),(2,2, 'More Info 5'),(3,1, 'More Info 6'),(4,1, 'More Info 7')
--select query needed for desired output (using a CTE)
; with iter_max as
(
select td.date_id
, max(td.iteration) as iteration_max
from #table_dates as td
group by td.date_id
)
select tc.*
, td.*
from #table_core as tc
left join iter_max as im on tc.core_id = im.date_id
inner join #table_dates as td on im.date_id = td.date_id
and im.iteration_max = td.iteration
select *
from
(
SELECT table_DATES.[date-ID], *
, row_number() over (partition by table_CORE date-ID order by iteration desc) as rn
FROM table_CORE
LEFT JOIN table_DATES
ON [table_CORE].[core-ID] = table_DATES.[date-ID]
WHERE table_CORE.[core-ID] Like '*'
) tt
where tt.rn = 1
ORDER BY [core-ID]

Update SQL Server query with order by clause [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I have the following SQL Server query that I would like to add order by clause. Can someone take a look at the QRY.
declare #variable int
set #variable = 0
UPDATE r_recipes_tmp
SET #variable = stepId = #variable + 1
I was trying the following with no luck.
declare #variable int
set #variable = 0
UPDATE r_recipes_tmp
SET #variable = stepId = #variable + 1
WHERE stepId IN (SELECT stepId
FROM r_recipes_tmp
WHERE recipename = 'test'
ORDER BY stepid DESC)
Thank you
It seems like you want to sort the rows in the descending order of stepId, then assign new consecutive values to stepId but this time in the ascending order, so essentially you want to reverse the order of rows if stepId was the sorting criterion. Or, using an example (which you haven't provided), turn a row set like this:
stepId someColumn
------ ----------
7 AAA
4 BBB
2 DDD
1 CCC
into this:
stepId someColumn
------ ----------
1 AAA
2 BBB
3 DDD
4 CCC
If that is indeed so and if you are using SQL Server 2005 or later version, you could use a CTE and the ROW_NUMBER() function like this:
WITH newIDs AS (
SELECT
stepId,
newStepId = ROW_NUMBER() OVER (ORDER BY stepId DESC)
FROM atable
)
UPDATE newIDs
SET stepId = newStepId
;
The ROW_NUMBER function assigns row numbers in the descending order of stepId, returning them alongside corresponding current values of stepId. Since the newIDs CTE derives rows from a single table, that makes the CTE updatable, so you can use it as the target of UPDATE and simply assign every stepId the newly generated row number.

Resources