I seem to be stuck on this and can't find a solution having had a look around.
I have an SQL table who's first row looks something like this:
Name Val1 Val2 Val3
John 1000 2000 3000
What I need to do is Select the largest value within this row i.e. 3000
Obviously if these values were in a column rather than row you could just use SELECT MAX(column) FROM table to get the largest value in the column. Is there an equivalent of this for finding the max value in a row?
I have also had a look at the uses of PIVOT and UNPIVOT but I don't think they are useful to me here..
The only way I have been able to do it is to create a temp table and insert each value into a single column like so:
CREATE TABLE #temp (colvals float)
INSERT INTO #temp (colvals)
SELECT Val1 FROM table WHERE ID=1
UNION
SELECT Val2 FROM table WHERE ID=1
UNION
SELECT Val3 FROM table WHERE ID=1
--------------------------------------------
SELECT MAX(colvals) FROM #temp
--------------------------------------------
DROP TABLE #temp
However I feel this is rather slow especially as my table has a lot more columns than the snippet I have shown above.
Any ideas?
Thanks in advance.
You can build a reference table for columns by APPLY and use native MAX()
-- Sample Data
declare #data table (Name varchar(10), Val1 int, Val2 int, Val3 int, Val4 int, Val5 int, Val6 int)
insert #data values
('John', 1000, 2000, 3000, 4000, 5000, 6000),
('Mary', 1, 2, 3, 4, 5, 6)
select Name, MaxValue from
#data
cross apply
(
select max(value) as MaxValue
from
(values
(Val1),(Val2),(Val3),(Val4),(Val5),(Val6) -- Append here
) t(value)
) result
SQL Fiddle
select MAX(case when c1 > c2 and c1 > c3 then c1
when c2 > c3 then c2
else c3
end)
from tablename
You need something like this:
SELECT *, Row_Number() OVER (ORDER BY GETDATE()) Rowid INTO #temp From yourtable
DECLARE #Columns AS Varchar(MAX)
SET #Columns =''
SELECT #Columns = #Columns + ',[' + name + ']' FROM tempdb..syscolumns
WHERE id=object_id('tempdb..#temp') AND name <> 'Rowid'
SELECT #Columns = Right(#Columns, len(#Columns)-1)
exec ('Select Rowid,Max(val) maxval from #temp t Unpivot(val For data in (' + #Columns + ')) as Upvt Group by Rid')
Drop table #temp
Use math logic:
select
case
when val1 >= val2 and val1 >= val2 then val1
when val2 >= val1 and val2 >= val3 then val2
else val3
end maxVal
from mytable
where id = 1
I think you were on the right track when you looked at unpivot as an option. Becaue that's exactly what you want to do - you have a pivot table, and you want the unpivoted value from it. Here's what I came up with:
declare #base table (Name char(4), Val1 int, Val2 int ,Val3 int);
insert into #base (Name, Val1 , Val2 , Val3) values ('John' , 1000 , 2000 , 3000);
select name, max(value) as max_value
from (
select name, valuetype, value
from #base b
unpivot ( value for valuetype in (Val1 , Val2 , Val3)) as u
) as up
group by name
To expand to your whole table, you can then just add more column names to the unpivot row:
unpivot ( value for valuetype in (Val1 , Val2 , Val3, ... more values here...)) as u
You could always replicate this answer Is there a Max function in SQL Server that takes two values like Math.Max in .NET?
-- Sample Data
declare #data table (Name varchar(10), Val1 int, Val2 int, Val3 int, Val4 int, Val5 int, Val6 int)
insert #data values
('John', 1000, 2000, 3000, 4000, 5000, 6000),
('Mary', 1, 2, 3, 4, 5, 6),
('Tony66', 1, 2, 3, 4, 5, 66),
('Tony55', 1, 2, 3, 4, 55, 6),
('Tony44', 1, 2, 3, 44, 5, 6),
('Tony33', 1, 2, 33, 4, 5, 6),
('Tony22', 1, 22, 3, 4, 5, 6),
('Tony11', 11, 2, 3, 4, 5, 6)
SELECT name,
(SELECT MAX(value)
FROM (VALUES (Val1),(Val2), (Val3), (Val4), (Val5), (Val6)) AS AllValues(value)) AS 'MaxValue'
FROM #data
Related
I have a table something like this:
CREATE TABLE #TempTable
(
COLUMN1 INT,
COLUMN2 INT
)
INSERT INTO #TempTable
(
COLUMN1,
COLUMN2
)
VALUES
(1, 5),
(2, 4),
(3, NULL),
(4, 2),
(5, NULL)
I want to update the COLUMN2 to add auto increment using a MAX value from a column.
I tried this query:
DECLARE #maxNumber INT = 0;
SELECT #maxNumber = ISNULL(MAX(COLUMN2), 0) + 1
FROM #TempTable
SELECT #maxNumber
CREATE SEQUENCE [tempSqu] AS [int] START
WITH #maxNumber INCREMENT BY 1
UPDATE #TempTable
SET COLUMN2 = NEXT VALUE FOR [tempSqu]
WHERE COLUMN2 IS NULL
DROP sequence [tempSqu]
The output:
COLUMN1 COLUMN2
--------------------
1 5
2 4
3 6
4 2
5 7
Try something like this:
UPDATE tmp
SET tmp.COLUMN2 = #maxNumber, #maxNumber = #maxNumber + 1
FROM #TempTable tmp
WHERE tmp.COLUMN2 IS NULL
You can do the same with dynamic SQL something like this:
DECLARE #maxNumber INT = 0
,#sequenceDSQL VARCHAR(4000);
SELECT #maxNumber = ISNULL(MAX(COLUMN2), 0) + 1
FROM #TempTable
SET #sequenceDSQL = 'CREATE SEQUENCE [dbo].[tempSqu] AS [int] START WITH '
+ CAST(#maxNumber AS VARCHAR(19)) +
'INCREMENT BY 1 UPDATE #TempTable
SET COLUMN2 = NEXT VALUE FOR [tempSqu]
WHERE COLUMN2 IS NULL
DROP sequence [tempSqu]'
EXEC (#sequenceDSQL)
You can also try with Row_Number() function and inner join update as shown below.
Note: I have provided the logic in the comment with the query.
CREATE TABLE TempTable
(
COLUMN1 INT,
COLUMN2 INT
)
INSERT INTO TempTable ( COLUMN1, COLUMN2 )
VALUES (1, 5), (2, 4), (3, NULL), (4, 2), (5, NULL), (6, 9), (7, NULL), (8, NULL)
--Getting the maximum value available in the table.
declare #maxValue int = (Select top 1 Column2 from TempTable
where Column2 is not null order by column2 desc)
Update
t set t.column2 = #maxValue + SrNo --Update with max value with SrNo as sequence
from TempTable t inner join (
SELECT COLUMN1
,row_number() OVER (
ORDER BY (
SELECT NULL
)
) AS SRNO --It will always give value in sequence like 1, 2, 3, ...
FROM TempTable where COLUMN2 is null
)temp on t.Column1 = temp.Column1
where t.column2 is null
--Selecting the record after update
Select * from TempTable order by column1
Here is the live db<>fiddle.
I'm trying to create result set with 3 columns. Each column coming from the summation of 1 Column of Table A but grouped by different ID's. Here's an overview of what I wanted to do..
Table A
ID Val.1
1 4
1 5
1 6
2 7
2 8
2 9
3 10
3 11
3 12
I wanted to create something like..
ROW SUM.VAL.1 SUM.VAL.2 SUM.VAL.3
1 15 21 33
I understand that I can not get this using UNION, I was thinking of using CTE but not quite sure with the logic.
You need conditional Aggregation
select 1 as Row,
sum(case when ID = 1 then Val.1 end),
sum(case when ID = 2 then Val.1 end),
sum(case when ID = 3 then Val.1 end)
From yourtable
You may need dynamic cross tab or pivot if number of ID's are not static
DECLARE #col_list VARCHAR(8000)= Stuff((SELECT ',sum(case when ID = '+ Cast(ID AS VARCHAR(20))+ ' then [Val.1] end) as [val.'+Cast(ID AS VARCHAR(20))+']'
FROM Yourtable
GROUP BY ID
FOR xml path('')), 1, 1, ''),
#sql VARCHAR(8000)
exec('select 1 as Row,'+#col_list +'from Yourtable')
Live Demo
I think pivoting the data table will yield the desired result.
IF OBJECT_ID('tempdb..#TableA') IS NOT NULL
DROP TABLE #TableA
CREATE TABLE #TableA
(
RowNumber INT,
ID INT,
Value INT
)
INSERT #TableA VALUES (1, 1, 4)
INSERT #TableA VALUES (1, 1, 5)
INSERT #TableA VALUES (1, 1, 6)
INSERT #TableA VALUES (1, 2, 7)
INSERT #TableA VALUES (1, 2, 8)
INSERT #TableA VALUES (1, 2, 9)
INSERT #TableA VALUES (1, 3, 10)
INSERT #TableA VALUES (1, 3, 11)
INSERT #TableA VALUES (1, 3, 12)
-- https://msdn.microsoft.com/en-us/library/ms177410.aspx
SELECT RowNumber, [1] AS Sum1, [2] AS Sum2, [3] AS Sum3
FROM
(
SELECT RowNumber, ID, Value
FROM #TableA
) a
PIVOT
(
SUM(Value)
FOR ID IN ([1], [2], [3])
) AS p
This technique works if the ids you are seeking are constant, otherwise I imagine some dyanmic-sql would work as well if changing ids are needed.
https://msdn.microsoft.com/en-us/library/ms177410.aspx
I would like to get the desired output marked in green
the data points for each id get put into a single cell
Basically take all the events that have happened with A and attach it in the same order
Use Stuff Function:
DECLARE #tblTest AS Table(
ID INT,
EVENT VARCHAR(5)
)
INSERT INTO #tblTest VALUES
(1,'A'),
(1,'A'),
(1,'C'),
(2,'A'),
(2,'B'),
(2,'C')
SELECT DISTINCT
T1.ID,
STUFF
(
(SELECT '' + convert(varchar(10), T2.EVENT, 120)
FROM #tblTest T2
where T1.ID = T2.ID
FOR XML PATH (''))
, 1, 0, '') AS EVENT
FROM #tblTest T1
You can use FOR XML:
SELECT DISTINCT
ID,
(SELECT [EVENT] +''
FROM YourTable
WHERE ID = y.ID
FOR XML PATH('')
) as [EVENT]
FROM YourTable y
Output:
ID EVENT
1 AABCD
2 AABBCC
You can use UDF to do so as follows:
CREATE TABLE t(
id INT,
col CHAR(1)
);
INSERT INTO t VALUES (1,'a');
INSERT INTO t VALUES (1,'b');
INSERT INTO t VALUES (1,'c');
INSERT INTO t VALUES (1,'d');
INSERT INTO t VALUES (2,'e');
INSERT INTO t VALUES (2,'f');
INSERT INTO t VALUES (3,'g');
INSERT INTO t VALUES (4,'h');
The UDF (User defined function) -
USE [t]
GO
CREATE FUNCTION dbo.ConcatenateCols(#Id INT)
RETURNS VARCHAR(MAX)
AS
BEGIN
DECLARE #RtnStr VARCHAR(MAX)
SELECT #RtnStr = COALESCE(#RtnStr + '','') + col
FROM dbo.t
WHERE id = #Id AND col > ''
RETURN #RtnStr
END
GO
Finally the query and result:
SELECT id, dbo.ConcatenateCols(id) AS Cols -- UDF - ConcatenateCols(id)
FROM t GROUP BY Id
CREATE TABLE #temp(Id INt,Event Nvarchar(25))
INSERT INTO #temp
SELECT 1,
'A'
UNION ALL
SELECT 1,
'A'
UNION ALL
SELECT 1,
'B'
UNION ALL
SELECT 1,
'C'
UNION ALL
SELECT 1,
'D'
UNION ALL
SELECT 2,
'A'
UNION ALL
SELECT 2,
'A'
UNION ALL
SELECT 2,
'B'
UNION ALL
SELECT 2,
'B'
UNION ALL
SELECT 2,
'C'
UNION ALL
SELECT 2,
'C'
SELECT DISTINCT ID,
(SELECT [EVENT] +''
FROM #temp
WHERE ID = y.ID
FOR XML PATH('') ) AS [EVENT]
FROM #temp y
I have an SQL table with a structure similar to the following:
Name Value
(varchar) (bit)
__________________
Val1 1
Val2 1
Val3 0
Val4 0
Val1 0
Val2 0
Val3 0
Val4 1
So basically, I have two instances of the same row but with a different bit value. I want to retrieve distinct rows from this table, with the bit value being OR'ed. So for the given example, the result would look like:
Name Value
Val1 1 (1 | 0)
Val2 1 (1 | 0)
Val3 0 (0 | 0)
Val4 1 (0 | 1)
Can this be achieved?
I am working in Microsoft SQL Server 2012. Any kind of help is appreciated. Please do let me know if any further clarification is required.
Observing that "bitwise OR" has the same function as the aggregate function MAX (assuming all inputs are either 0 or 1, if any input is 1, the result is 1, otherwise 0) and accounting for the fact that we can't directly aggregate bit, this seems to work:
declare #t table (Name varchar(17) not null,Value bit not null)
insert into #t(Name,Value) values
('Val1',1),
('Val2',1),
('Val3',0),
('Val4',0),
('Val1',0),
('Val2',0),
('Val3',0),
('Val4',1)
select Name,CONVERT(bit,MAX(CONVERT(int,Value))) as Value
from #t group by Name
You can try this, hoping that value is numeric field with values 0 and 1.
SELECT Name, MAX(Value)
FROM [table]
GROUP BY Name
DECLARE #t TABLE (Name VARCHAR(10) NOT NULL, Value BIT NOT NULL)
INSERT INTO #t (Name, Value)
VALUES
('Val1', 1), ('Val2', 1), ('Val3', 0), ('Val4', 0),
('Val1', 0), ('Val2', 0), ('Val3', 0), ('Val4', 1)
SELECT Name, MAX(Value % 2)
FROM #t
GROUP BY Name
output -
---------- -----------
Val1 1
Val2 1
Val3 0
Val4 1
I am trying to write a query against the following dataset that will separate the last updated records based on a unique set of fields..
Assume for the following example the the unique set of fields is val1 + val2 + val3.
I tried using window functions to achieve this, but there seems to be another level of complexity for this example.
--DROP TABLE #demo;
-- assume there is a unique key on val1 + val2 + val3
CREATE TABLE #demo
(
id int NOT NULL,
val1 varchar(100) NOT NULL,
val2 varchar(100) NOT NULL,
val3 varchar(100) NOT NULL,
last_updated DATETIME NOT NULL,
active bit not null
);
INSERT INTO #demo VALUES
(0,'a','b','c', '20150817', 0),
(1,'a','b','c', '20150817', 0),
(2,'a','b','c', '20150817', 0),
(3,'a','b','c', '20150815', 0),
(4,'a','b','c', '20150815', 0),
(5,'d','e','f', '20150701', 0),
(6,'d','e','f', '20150630', 0),
(7,'d','e','f', '20150630', 0),
(8,'d','e','f', '20150630', 0)
-- using unique key columns, trying to get only those with the most recent date
SELECT *
, ROW_NUMBER() OVER(PARTITION BY val1, val2, val3 ORDER BY last_updated DESC) AS RowNum
FROM #demo
I am hoping to return only the highlighted records below (id: 0,1,2,5) with the query.
Is this possible? Thanks in advance.
SELECT *
FROM (
SELECT *
, DENSE_RANK() OVER(PARTITION BY val1, val2, val3
ORDER BY last_updated DESC) AS RowNum
FROM #demo
)t
WHERE RowNum = 1
select d.* from
demo d join
(
SELECT val1,val2,val3 ,
max(last_updated) as mx
FROM demo
group by val1,val2,val3) x
on x.val1 = d.val1 and x.val2 = d.val2 and x.val3 = d.val3
and x.mx = d.last_updated
This is one more approach.
Fiddle