Finding max value of multiple columns in Sql - sql

How can I find maximum value on multiple columns.
This is what I have so far.
With Temp AS (
SELECT P.ID AS 'Product_ID',
P.ProductCode AS 'Product_Code',
P.Name AS 'Product_Name',
P.SellPrice AS 'SellPrice',
P.SellPrice+(P.SellPrice*TVA/100) AS 'PricePerUnit',
P.TVA AS 'TVA',
P.Discount AS 'Discount_Product',
0 AS 'Discount_Code',
0 AS 'Discount_Newsletter',
V.ID AS 'Variant_ID',
V.Nume AS 'Variant_Name',
V.Stock-V.Reserved AS 'Quantity_MAX',
T.Quantity AS 'Quantity',
I.ImageName AS 'Image',
0 AS 'Is_Kit'
FROM TemporaryShoppingCart T
INNER JOIN ProductVariant V ON V.ID=T.Variant_ID
INNER JOIN Product P ON P.ID=V.ProductID
LEFT JOIN ProductImage I ON I.ProductID=P.ID AND DefaultImage=1
WHERE T.ID=#ID AND T.Variant_ID!=0
) SELECT t.* ,MAX(MAXValue) FROM (SELECT (T.Discount_Product) AS 'MAXValue'
UNION ALL
SELECT (T.Discount_Code)
UNION ALL
SELECT (T.Discount_Newsletter)) as 'maxval' //error
FROM Temp T
This code is giving me the error: Incorrect syntax near 'maxval'.

Are you simply looking for GREATEST?
SELECT
t.*,
GREATEST(T.Discount_Product, T.Discount_Code, T.Discount_Newsletter) as 'maxval'
FROM Temp T;
However GREATEST Returns NULL when a value is NULL, so you might want to care about this, too. For instance:
SELECT
t.*,
GREATEST
(
coalesce(T.Discount_Product,0),
coalesce(T.Discount_Code, 0),
coalesce(T.Discount_Newsletter, 0)
) as 'maxval'
FROM Temp T;
EDIT: In case GREATEST is not available in your dbms you can use a case expression.
SELECT
t.*,
CASE
WHEN coalesce(T.Discount_Product, 0) > coalesce(T.Discount_Code, 0)
AND coalesce(T.Discount_Product, 0) > coalesce(T.Discount_Newsletter, 0)
THEN coalesce(T.Discount_Product, 0)
WHEN coalesce(T.Discount_Code, 0) > coalesce(T.Discount_Product, 0)
AND coalesce(T.Discount_Code, 0) > coalesce(T.Discount_Newsletter, 0)
THEN coalesce(T.Discount_Code, 0)
ELSE coalesce(T.Discount_Newsletter, 0)
END
FROM Temp T;
EDIT: To get your own statement syntactically correct, do:
SELECT
t.*,
(
select MAX(Value)
FROM
(
SELECT T.Discount_Product AS Value
UNION ALL
SELECT T.Discount_Code
UNION ALL
SELECT T.Discount_Newsletter
) dummy -- T-SQL requires a name for such sub-queries
) as maxval
FROM Temp T;

You probably want to have each Select statement to have a From clause.

SELECT max( GREATEST(col1,col2, col3,col4, col5, col6, col7, col8, col9,col10, col11, col12)) AS 'MAXDATE' FROM table_name

Consider we have three tables C1,C2 and C3.
The table data are as follow :-
To find the 1st max value we use the following sql query:
Query:
;WITH CTE AS
(
SELECT (T.Marks) AS Highest, ROW_NUMBER() OVER (ORDER BY MAX(T.MARKS) DESC) AS R FROM
(
SELECT (c1.Marks) AS Marks FROM c1
UNION
SELECT (c2.Marks) AS Marks FROM c2
UNION
SELECT (c3.Marks) AS Marks FROM c3
) AS T GROUP BY (T.Marks) )
SELECT Highest FROM CTE WHERE R = 1
To find the next max values change the value of R in last line of query.

Related

How to define unique value in union if two rows are not same data

I'm creating a simple SQL query with union, the result is returned correctly, but how to set a default value in a dummy column if the union result has two rows for one value?
If the result returned two values for one employee, then the dummy column is 'N' for the first value and 'Y' for the second value.
And if the result returned only one value for the employee, then the dummy column is 'Y'
How to achieve that?
This is the query that I'm using
select
dbo.employee,
dbo.starting_date
from
table_1
union
select
dbo.employee,
dbo.hiring_date
from
table_2
With a CTE:
with cte as (
select dbo.employee, dbo.starting_date date from table_1
union all
select dbo.employee, dbo.hiring_date date from table_2
)
select
t.*,
case when exists (
select 1 from cte
where employee = t.employee and date > t.date
) then 'N' else 'Y' end dummycolumn
from cte t
You can use window functions for this:
select t.employee, t.date,
(case when 1 = row_number() over (partition by t.employee order by t.date)
then 'Y' else 'N'
end) as dummy
from ((select t1.employee, t1.starting_date as date
from table_1 t1
) union all
(select t2.employee, t2.starting_date as date
from table_2 t2
)
) t

How to use Dynamic Lag function to avoid joining a table to itself to retrieve date value

I'm currently writing code in SQL to add the column in red to the following table:
The logic is the following:
For every row:
if flag for this row =1 then use date of this row
if flag for this row =0 then find the latest row (based on date) on which flag was = 1 for the same party and return the date of that row. If no such row exists, return null
I've found a way to do this by joining the table to itself but I would like to avoid doing that as the size of the table is pretty massive.
What I have
select b.*, a.date,
from table a left join table b on a.party=b.party
where a.flag =1
Someone told me I could use the lag function, the partition over function and a case when to return the value I'm after but I haven't been able to figure it out.
Can someone help? Thank you so much!
try this
DECLARE #tab1 TABLE(PARTY CHAR(1),DATE DATE,Flag bit)
INSERT INTO #tab1
SELECT 'A','7-24-2018',1 Union ALL
SELECT 'A','7-28-2018',0 Union ALL
SELECT 'A','7-29-2018',0 Union ALL
SELECT 'A','7-29-2018',0 Union ALL
SELECT 'B','7-13-2018',1 Union ALL
SELECT 'B','7-17-2018',0 Union ALL
SELECT 'B','7-18-2018',0 Union ALL
SELECT 'C','7-8-2018',1 Union ALL
SELECT 'C','7-13-2018',0 Union ALL
SELECT 'C','7-19-2018',0 Union ALL
SELECT 'C','7-19-2018',0 Union ALL
SELECT 'C','7-20-2018',0
select t.*,
max(case when flag = 1 then date end) over (partition by PARTY order by date) as [Last Flag On Date]
from #tab1 t
try this :->
select b.*, a.date, from table a left join table b on a.party=b.party where a.flag = CASE WHEN a.flag = 1 THEN a.date WHEN a.flag = 0 THEN ( SELECT date FROM ( SELECT TOP 1 row_number() OVER ( ORDER BY a.date DESC ) rs , a.date FROM a WHERE a.flag = 1 GROUP BY a.date) s ) END
use CROSS APPLY() to obtain the latest row with flag 1
SELECT *
FROM yourtable t
CROSS APPLY
(
SELECT TOP 1 x.Date as [Last flag on date]
FROM yourtable x
WHERE x.Party = t.Party
AND x.Flag = 1
ORDER BY x.Date desc
) d
Yes it can be done by joining table, if written properly.
#Sahi query is also good and simple.
Since you were asking for Dynamic LAG()
This query may or may not be very performant,but it certainly worth learning.
Test this with various sample data and tell me for which scenario it do not work.
So that I correct my script accordingly.
DECLARE #tab1 TABLE(PARTY CHAR(1),DATE DATE,Flag bit)
INSERT INTO #tab1
SELECT 'A','7-24-2018',1 Union ALL
SELECT 'A','7-28-2018',0 Union ALL
SELECT 'A','7-29-2018',0 Union ALL
SELECT 'A','7-29-2018',0 Union ALL
SELECT 'B','7-13-2018',1 Union ALL
SELECT 'B','7-17-2018',0 Union ALL
SELECT 'B','7-18-2018',0 Union ALL
SELECT 'C','7-8-2018',1 Union ALL
SELECT 'C','7-13-2018',0 Union ALL
SELECT 'C','7-19-2018',0 Union ALL
SELECT 'C','7-19-2018',0 Union ALL
SELECT 'C','7-20-2018',0;
WITH cte
AS (SELECT *,
Row_number()
OVER (
partition BY party
ORDER BY flag DESC, [date] DESC ) rn
FROM #tab1)
SELECT *,
CASE
WHEN flag = 1 THEN [date]
ELSE Lag([date], (SELECT TOP 1 a.rn - a1.rn
FROM cte a1
WHERE a1.party = a.party))
OVER (
ORDER BY party )
END
FROM cte a

Oracle Database Rownum Between

There are 25 records in this sql query
I want to get between 5 and 10. How can I do it ?
I use 11g
select
(
select count(*) as sayfasayisi
from konular t
where t.kategori is not null
) as sayfasayisi,
t.id,
t.uye,
t.baslik,t.mesaj,t.kategori,t.tarih,
t.edittarih,t.aktif,t.indirimpuani,t.altkategori,t.link,
nvl(
(select case when t.id = f.konuid and f.uye = 'test' then '1' else '0' end
from takipkonu f where t.id = f.konuid and f.uye = 'test'), '0') as takip
from konular t
where t.kategori is not null
You can use ROW_NUMBER() to assign a row number based on some ordering logic contained in your current query, e.g. a certain column. Then, retain only the 5th to 10th records:
select t.*
from
(
select
(
select count(*) as sayfasayisi
from konular t
where t.kategori is not null
) as sayfasayisi,
ROW_NUMBER() OVER (ORDER BY some_col) rn,
t.id,
t.uye,
...
) t
where t.rn between 5 and 10;

How to get Original Rows filtered by a HAVING Condition?

What is the method in T-SQL to select the orginal values limited by a HAVING attribute. For example, if I have
A|B
10|1
11|2
10|3
How would I get all the values of B (Not An Average or some other summary stat), Grouped by A, having a Count (Occurrences of A) greater than or equal two 2?
Actually, you have several options to choose from
1. You could make a subquery out of your original having statement and join it back to your table
SELECT *
FROM YourTable yt
INNER JOIN (
SELECT A
FROM YourTable
GROUP BY
A
HAVING COUNT(*) >= 2
) cnt ON cnt.A = yt.A
2. another equivalent solution would be to use a WITH clause
;WITH cnt AS (
SELECT A
FROM YourTable
GROUP BY
A
HAVING COUNT(*) >= 2
)
SELECT *
FROM YourTable yt
INNER JOIN cnt ON cnt.A = yt.A
3. or you could use an IN statement
SELECT *
FROM YourTable yt
WHERE A IN (SELECT A FROM YourTable GROUP BY A HAVING COUNT(*) >= 2)
A self join will work:
select B
from table
join(
select A
from table
group by 1
having count(1)>1
)s
using(A);
You can use window function (no joins, only one table scan):
select * from (
select *, cnt=count(*) over(partiton by A) from table
) as a
where cnt >= 2

Using SQL to get the previous rows data

I have a requirement where I need to get data from the previous row to use in a calculation to give a status to the current row. It's a history table. The previous row will let me know if a data has changed in a date field.
I've looked up using cursors and it seems a little complicated. Is this the best way to go?
I've also tried to assgin a value to a new field...
newField =(Select field1 from Table1 where "previous row") previous row is where I seem to get stuck. I can't figure out how to select the row beneath the current row.
I'm using SQL Server 2005
Thanks in advance.
-- Test data
declare #T table (ProjectNumber int, DateChanged datetime, Value int)
insert into #T
select 1, '2001-01-01', 1 union all
select 1, '2001-01-02', 1 union all
select 1, '2001-01-03', 3 union all
select 1, '2001-01-04', 3 union all
select 1, '2001-01-05', 4 union all
select 2, '2001-01-01', 1 union all
select 2, '2001-01-02', 2
-- Get CurrentValue and PreviousValue with a Changed column
;with cte as
(
select *,
row_number() over(partition by ProjectNumber order by DateChanged) as rn
from #T
)
select
C.ProjectNumber,
C.Value as CurrentValue,
P.Value as PreviousValue,
case C.Value when P.Value then 0 else 1 end as Changed
from cte as C
inner join cte as P
on C.ProjectNumber = P.ProjectNumber and
C.rn = P.rn + 1
-- Count the number of changes per project
;with cte as
(
select *,
row_number() over(partition by ProjectNumber order by DateChanged) as rn
from #T
)
select
C.ProjectNumber,
sum(case C.Value when P.Value then 0 else 1 end) as ChangeCount
from cte as C
inner join cte as P
on C.ProjectNumber = P.ProjectNumber and
C.rn = P.rn + 1
group by C.ProjectNumber
This really depends on what tells you a row is a "Previous Row". however, a self join should do what you want:
select *
from Table1 this
join Table2 prev on this.incrementalID = prev.incrementalID+1
If you have the following table
CREATE TABLE MyTable (
Id INT NOT NULL,
ChangeDate DATETIME NOT NULL,
.
.
.
)
The following query will return the previous record for any record from MyTable.
SELECT tbl.Id,
tbl.ChangeDate,
hist.Id,
hist.ChangeDate
FROM MyTable tbl
INNER JOIN MyTable hist
ON hist.Id = tbl.Id
AND hiost.ChangeDate = (SELECT MAX(ChangeDate)
FROM MyTable sub
WHERE sub.Id = tbl.Id AND sub.ChangeDate < tbl.ChangeDate)