SQL Case MAX WHEN LIKE - sql

I would like to create a case statement or a rank over statement for a particular outlier case I have.
I am not sure how to write a case statement utilizing CASE (pseudo code)
WHEN MAX Total_Revenue COMPANY like 'ABC%'
else COMPANY
i have tried rank over, but it is not working:
,RANK() OVER(COMPANY LIKE 'DEF%' ORDER BY Total_Revenue DESC) AS grp
Current table:
Company Total_Revenue
ABC 10
DEF1 25 --This row will NOT be selected as its less than
DEF2 35 -- this row will be kept
GHI3 65
JKL9 100
Ouput table:
Company Total_Revenue
ABC 10
DEF2 35 --kept
GHI3 65
JKL9 100

There's quite a few ways to do what it seems like you are after:
Using a subquery to find max revenue for each comp:
SELECT Company, Total_Revenue
FROM myTable
INNER JOIN
(
SELECT Left(Company, 3) as leftcomp,
max(Total_Revenue) as maxTotalRevenue
FROM mytable
GROUP BY Left(Company, 3)
) mt
ON Left(myTable.Company, 3) = mt.leftcomp
AND myTable.Total_Revenue = mt.maxTotalRevenue;
Window function that is later filtered by Where:
SELECT *
FROM
(
SELECT Company,
Total_Revenue,
MAX(Total_Revenue) OVER (PARTITION BY Left(Company, 3)) as maxTotalRevenue
FROM myTable
) mt
WHERE Total_Revenue = maxTotalRevenue;
Correlated subquery in the WHERE clause:
SELECT *
FROM myTable mt1
Where Total_Revenue =
(
SELECT max(total_revenue)
FROM myTable
WHERE Left(myTable.Company, 3) = Left(mt1.Company, 3)
);
SQLFiddle here

You seems want row_number() function :
SELECT t.*
FROM (SELECT *, ROW_NUMBER() OVER (PARTITION BY LEFT(Company, 3) ORDER BY Total_Revenue DESC) AS Seq
FROM table t
) t
WHERE Seq = 1;

This is what you want ?
select * from t
where
Company not in (
select Company from t where Company like '%DEF%' order by Company desc offset 1
)

use aggregate function max() and sub-query
select * from Yourtable t1
where t1.Total_Revenue in (
select max(T.Total_Revenue ) as Total_Revenue from
(
select case when Company like'%DEF%' then 'DEF'
else Company end as Company ,
Total_Revenue from Yourtable
) as T
group by T.Company
)
http://sqlfiddle.com/#!18/e896c/5
Company Total_Revenue
ABC 10
DEF2 35
GHI3 65
JKL9 100

Related

Max with other fields in SQL Server

Here is my query :
SELECT id, id_gamut, position from operation
It returns :
N°1) id id_gamut position
--------------------------
1 19 1
2 19 2
3 19 3
4 25 1
5 25 2
6 12 1
I need to group it by id_gamut with the max position to get a result like this :
N°2) id id_gamut position
--------------------------
3 19 3
5 25 2
6 12 1
Then i tried something like this :
SELECT gamut, Max(position) from(
SELECT id, gamut, position from operation) as req
GROUP BY gamut
It works, but my problem is i really need to have the field 'id' in my query, but if i add it like this :
SELECT id, gamut, Max(position) from(
SELECT id, gamut, position from operation) as req
GROUP BY gamut,id
My group by is broken and i have a result like result N°1
How can i group by id_gamut with max position and having the 'id' field too ?
using top with ties with row_number()
select top 1 with ties
id
, id_gamut
, position
from operation
order by row_number() over (
partition by id_gamut
order by position desc
)
Or using a common table expression with row_number()
;with cte as (
select *
, rn = row_number() over (
partition by id_gamut
order by position desc
)
from operation
)
select
id
, id_gamut
, position
from cte
where rn = 1
Or as a subquery without the cte
select
id
, id_gamut
, position
from (
select *
, rn = row_number() over (
partition by id_gamut
order by position desc
)
from operation
) s
where rn = 1
Or with cross apply()
select distinct
x.id
, o.id_gamut
, x.position
from operation o
cross apply (
select top 1
id
, position
from operation i
where i.id_gamut = o.id_gamut
order by position desc
) x
Or with not exists() (This will return more than 1 row per id_gamut if there is more than one row with the same max position)
select *
from operation o
where not exists (
select 1
from operation i
where i.id_gamut = o.id_gamut
and i.position > o.position
)
Or with not exists() (Additional clause to return highest id in the event of multiple rows with the same max position)
select *
from operation o
where not exists (
select 1
from operation i
where i.id_gamut = o.id_gamut
and (i.position > o.position
or (i.position = o.position and i.id > o.id)
)
)
rextester demo: http://rextester.com/INV77202
Using ROW_NUMBER() inside Common Table Expression
WITH CTE AS
(
SELECT id, id_gamut, position
, ROW_NUMBER() OVER (PARTITION BY id_gamut ORDER BY position DESC) AS Rn
FROM operation
)
SELECT * FROM CTE WHERE Rn = 1
Use MAX function and GROUP BY clause :
SELECT *
FROM table1
JOIN
(
SELECT id_gamut,MAX(position) position
GROUP BY id_gamut
) A ON A.id_gamut = table1.id_gamut AND A.position = table1.position

Self-join a table in SQL Server 2008

I would like to use INNER JOIN on one table. But I get this error message:
Msg 208, Level 16, State 1, Line 1
Invalid object name 'a'.
My query is :
select *
from
(select
*,
ROW_NUMBER() OVER (ORDER BY GoodMainCode) as row
from [SarMem].[dbo].[Book_Data1]
where GoodName like '%A%' and GroupCode = 115) a
inner join a b on b.GoodMainCode = a.GoodMainCode
where a.row > 0 and a.row <= 100
updated
Do it with cte:
;with a as(select *, ROW_NUMBER() OVER (ORDER BY GoodMainCode) as row
from [SarMem].[dbo].[Book_Data1]
where GoodName like '%A%' and GroupCode = 115)
select * from a
join a b on b.GoodMainCode = a.GoodMainCode
where a.row > 0 and a.row <= 100
Maybe something like that?
WITH List AS (
SELECT
ROW_NUMBER() OVER (ORDER BY GoodMainCode) AS Row, *
FROM
[SarMem].[dbo].[Book_Data1]
WHERE
( GoodName like '%A%' )
AND ( GroupCode = 115 )
)
SELECT * FROM List WHERE Row between 1 and 100
I think here a is an alias name not the table name. So SQL SERVER won't allow a to create one more alias b.
So if you wanna use same table as a, then you have to rewrite subquery for b also.
Like,
select * from (
select *,ROW_NUMBER() OVER (ORDER BY GoodMainCode) as row from [SarMem].[dbo].[Book_Data1] where GoodName like '%A%' and GroupCode = 115 ) a
INNER JOIN (
select *,ROW_NUMBER() OVER (ORDER BY GoodMainCode) as row from [SarMem].[dbo].[Book_Data1] where GoodName like '%A%' and GroupCode = 115 ) b on b.GoodMainCode = a.GoodMainCode where a.row > 0 and a.row <= 100

How can i select all other records without top five records?

Location TotalRevenue LocationID
Orugodawatta 10059135.78 OR
Kohuwala 7058537.73 KH
Koswaththa 6717136.02 KW
Havelock Town 5748932.59 HT
Negombo 5193678.33 NG
Induruwa 3017552.74 IA
Absdhku 2254281.21 AB
I have a table in sql server 2008. how can i select all other rows without top 5 records?
if my table had 100 records i can selece all other 95 records without top 5 records. please help me
Try this.
SELECT * FROM MyTable WHERE LOCATION NOT IN (SELECT TOP 5 LOCATION FROM MyTable)
SELECT TOP (SELECT Count(*) - 5 FROM tableName WHERE YOUR_WHERE_CLAUSE) *
FROM tableName
WHERE YOUR_WHERE_CLAUSE
ORDER BY COLUMN_NAME DESC
suppose you get Top 5 records by Query
select Top 5 *
from Table_name
order by Location desc
So to get your 95 records
select Top 100 *
from Table_name
order by Location desc
except
select Top 5 *
from Table_name
order by Location desc
Select all in first CTE, select top 5 in second, and just use EXCEPT :
WITH CTE_ALL AS
(
SELECT
Location ,
SUM(SellingPrice) AS [Total Revenue] ,
LocationID
FROM BI_LocWiseTopItems
WHERE ( GRNDate BETWEEN '' AND GETDATE() )
GROUP BY Location ,
LocationID
)
, CTE_TOP5 AS
(
SELECT TOP 5 * FROM CTE_ALL
ORDER BY [Total Revenue]
)
SELECT * FROM CTE_ALL
EXCEPT
SELECT * FROM CTE_TOP5
SQLFiddle DEMO - Simplified for CTE
; WITH top5 AS (
SELECT TOP 5
Location
, TotalRevenue
, LocationID
FROM your_table
ORDER
BY TotalRevenue DESC
)
SELECT Location
, TotalRevenue
, LocationID
FROM your_table
EXCEPT
SELECT Location
, TotalRevenue
, LocationID
FROM top5
SELECT * FROM tableName
EXCEPT (SELECT TOP(5)* FROM tableName )
Your entire query. Have a try
SELECT Location,[Total Revenue],LocationID
FROM
(
SELECT Location, SUM(SellingPrice) AS 'Total Revenue', LocationID
FROM BI_LocWiseTopItems
WHERE (GRNDate BETWEEN '' AND GETDATE())
GROUP BY Location, LocationID ORDER BY 'Total Revenue' desc
) AS temp
EXCEPT (
SELECT top(5)Location, SUM(SellingPrice) AS 'Total Revenue', LocationID
FROM BI_LocWiseTopItems
WHERE (GRNDate BETWEEN '' AND GETDATE())
GROUP BY Location, LocationID ORDER BY 'Total Revenue' desc
)

SQL-how to find the percentage

I have a table with following values id and amt
id amt amt%
1 500 16.7
2 600 20
3 900 30
4 1000 33.3
-----------------------------
3000 100%
I have to find the amt% for id=1 by dividing amt for id=1/sum(amt for all the ids).
How to write query for this in sql?
select id, amt, 100.0 * amt / (select sum(amt) from tab) as amt_percent
from tab
Mind 100.0, .0 is quite important it will "force" conversion ints to floats.
Added after comment:
select t.id, t.amt, 100.0 * t.amt / p.s as amt_percent
from tab t
join (
select id, sum(amt) as s
from tab
group by id
) p on p.id = t.id
and alternative way:
select id, amt,
100.0 * amt / (
select sum(amt)
from tab t1
where t1.id = t.id
) as amt_percent
from tab t
I prefer joining subquery - the first one.
You can try something like this:
SELECT
id, amt,
amt / (SELECT SUM(amt) FROM tabl) * 100 as amtperc
FROM tabl
select id, amt, 100*amt/(select NULLIF(sum(amt),0) from tbl) as "amt%"
from tbl
or maybe so
select t.id, t.amt, 100*amt/sm.s as "amt%"
from tbl t, (select NULLIF(sum(amt),0) as s from tbl) sm
edit check for dividing by zero
Assuming you are using Oracle (as in your previous question), try:
select id, amt, 100 * amt / sum(amt) over () amtperc
from your_table
select id, amt, 100 * amt/(case when (select sum(amt)as ss from tablename)>0 then
(select sum(amt)as ss from tablename) else 1 end) as [amt%] from tablename

How do I get records before and after given one?

I have the following table structure:
Id, Message
1, John Doe
2, Jane Smith
3, Error
4, Jane Smith
Is there a way to get the error record and the surrounding records? i.e. find all Errors and the record before and after them.
;WITH numberedlogtable AS
(
SELECT Id,Message,
ROW_NUMBER() OVER (ORDER BY ID) AS RN
FROM logtable
)
SELECT Id,Message
FROM numberedlogtable
WHERE RN IN (SELECT RN+i
FROM numberedlogtable
CROSS JOIN (SELECT -1 AS i UNION ALL SELECT 0 UNION ALL SELECT 1) n
WHERE Message='Error')
WITH err AS
(
SELECT TOP 1 *
FROM log
WHERE message = 'Error'
ORDER BY
id
),
p AS
(
SELECT TOP 1 l.*
FROM log
WHERE id <
(
SELECT id
FROM err
)
ORDER BY
id DESC
)
SELECT TOP 3 *
FROM log
WHERE id >
(
SELECT id
FROM p
)
ORDER BY
id
Adapt this routine to pick out your target.
DECLARE #TargetId int
SET #TargetId = 3
select *
from LogTable
where Id in (-- "before"
select max(Id)
from LogTable
where Id < #TargetId
-- target
union all select #TargetId
-- "after"
union all select min(Id)
from LogTable
where Id > #TargetId)
select id,messag from
(Select (Row_Number() over (order by ID)) as RNO, * from #Temp) as A,
(select SubRNO-1 as A,
SubRNO as B,
SubRNO+1 as C
from (Select (Row_Number() over (order by ID)) as SubRNO, * from #Temp) as C
where messag = 'Error') as B
where A.RNO = B.A or A.RNO = B.B or A.RNO = B.C
;WITH Logs AS
(
SELECT ROW_NUMBER() OVER (ORDER BY id), id, message as rownum FROM LogTable lt
)
SELECT curr.id, prev.id, next.id
FROM Logs curr
LEFT OUTER JOIN Logs prev ON curr.rownum+1=prev.rownum
RIGHT OUTER JOIN Logs next ON curr.rownum-1=next.rownum
WHERE curr.message = 'Error'
select id, message from tbl where id in (
select id from tbl where message = "error"
union
select id-1 from tbl where message = "error"
union
select id+1 from tbl where message = "error"
)
Get fixed number of rows before & after target
Using UNION for a simple, high performance query (I found selected answer WITH query above to be extremely slow)
Here is a high performance alternative to the WITH top selected answer, when you know an ID or specific identifier for a given record, and you want to select a fixed number of records BEFORE and AFTER that record. Requires a number field for ID, or something like date that can be sorted ascending / descending.
Example: You want to select the 10 records before and after a specific error was recorded, you know the error ID, and can sort by date or ID.
The following query gets (inclusive) the 1 result above, the identified record itself, and the 1 record below. After the UNION, the results are sorted again in descending order.
SELECT q.*
FROM(
SELECT TOP 2
id, content
FROM
the_table
WHERE
id >= [ID]
ORDER BY id ASC
UNION
SELECT TOP 1
id, content
FROM
the_table
WHERE
id < [ID]
ORDER BY id DESC
) q
ORDER BY q.id DESC