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
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
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
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
)
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
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