Need to find which invoice has the second-lowest total price among invoices that do not include a sale of a FiredAlways stove.
I can manage to get the lowest, but not the second lowest.
What I have:
SELECT TOP 1 WITH TIES
I.InvoiceNbr,
I.InvoiceDt,
I.TotalPrice
FROM INVOICE I
WHERE EXISTS(
SELECT TOP 2 WITH TIES
I.InvoiceNbr
FROM INVOICE I
WHERE EXISTS (
SELECT FK_InvoiceNbr
FROM INV_LINE_ITEM
WHERE FK_StoveNbr NOT IN
(SELECT S.SerialNumber
FROM STOVE AS S
WHERE S.Type = 'FiredAlways'))
ORDER BY I.TotalPrice DESC)
GROUP BY I.InvoiceNbr, I.InvoiceDt, I.TotalPrice
ORDER BY I.TotalPrice ASC;
Data:
[INVOICE](
[InvoiceNbr] [numeric](18, 0) NULL,
[InvoiceDt] [datetime] NULL,
[TotalPrice] [numeric](18, 2) NULL,
[FK_CustomerID] [numeric](18, 0) NULL,
[FK_EmpID] [numeric](18, 0) NULL
[INV_LINE_ITEM](
[LineNbr] [numeric](18, 0) NULL,
[Quantity] [numeric](18, 0) NULL,
[FK_InvoiceNbr] [numeric](18, 0) NULL,
[FK_PartNbr] [numeric](18, 0) NULL,
[FK_StoveNbr] [numeric](18, 0) NULL,
[ExtendedPrice] [numeric](18, 2) NULL
[STOVE](
[SerialNumber] [int] NOT NULL,
[Type] [char](15) NOT NULL,
[Version] [char](15) NULL,
[DateOfManufacture] [smalldatetime] NULL,
[Color] [varchar](12) NULL,
[FK_EmpId] [int] NULL,
Wanted Output:
Invoice # date Price
--------- ------------ -------
206 02/03/2002 28.11
Two general approaches to get the nth lowest:
DECLARE #tbl TABLE(SomeInt INT);
INSERT INTO #tbl VALUES(10),(2),(35),(44),(52),(56),(27);
--Use a TOP n on the inner select and a TOP 1 with a reverse order on the outer:
SELECT TOP 1 innertbl.SomeInt
FROM
(
SELECT TOP 2 SomeInt
FROM #tbl
GROUP BY SomeInt
ORDER BY SomeInt
) AS innertbl
ORDER BY innertbl.SomeInt DESC;
--use a CTE with DENSE_RANK() (thx to dnoeth for the hint)
WITH AddSortNumber AS
(
SELECT SomeInt
,DENSE_RANK() OVER(ORDER BY SomeInt) AS SortNumber
FROM #tbl
)
SELECT SomeInt
FROM AddSortNumber
WHERE SortNumber=2
Try This:
WITH cte AS
(
SELECT
I.InvoiceNbr,
I.InvoiceDt,
I.TotalPrice,
dense_rank() over( ORDER BY I.TotalPrice ASC) as dnrnk
FROM INVOICE I
INNER JOIN
Inv_LineITEM
ON InvoiceNbr = FK_InvoiceNbr
INNER JOIN
Stove
ON
FK_StoveNbr = SerialNumber
WHERE Type != 'FiredAlways'
)
select InvoiceNbr,
InvoiceDt,
TotalPrice from cte where dnrnk=2
SELECT TOP 1 TotalPrice FROM (
SELECT TOP 2 TotalPrice FROM invoice
ORDER BY TotalPrice DESC
) AS em ORDER BY TotalPrice ASC
Essentially:
Find the top 2 TotalPrice in descending order.
Of those 2, find the top TotalPrice in ascending order.
The selected value is the second-highest TotalPrice.
If the TotalPrice isn't distinct, you can use SELECT DISTINCT TOP ... instead.
Related
In my query I'm Selecting row by row closing balance. It's consume 100% CPU while executing is sql server 2014.
Here is my query:
;WITH summary(id,reference_id,entry_date,particular,remarks,debit,credit,balance)AS(
SELECT
id,
reference_id,
entry_date,
particular,
remarks,
debit,
credit,
(credit-debit)+(SELECT ISNULL(SUM(l.credit-l.debit) ,0) FROM member_transaction l WHERE l.entry_date<a.entry_date AND l.member_id=#mId AND is_succeed=1 AND isnull(l.reference_id,0) NOT IN(SELECT user_reference_id FROM recharge_request WHERE status='Failure'))AS balance
FROM member_transaction a
WHERE member_id=#mId AND is_succeed=1
AND isnull(reference_id,0) NOT IN(SELECT user_reference_id FROM recharge_request WHERE status='Failure')),
openingbalance(
id,
reference_id,
entry_date,
particular,
remarks,
debit,
credit,
balance
)AS(SELECT TOP 1 0,'','','OPENING BALANCE','',0,0,balance FROM summary WHERE entry_date<'2017/03/10' ORDER BY entry_date DESC
)SELECT * FROM openingbalance UNION SELECT * FROM summary ORDER BY entry_date DESC
Is there any other way to calculate row by row closing balance on every transaction? Please help me to solve this problem.
HERE is table structure:
CREATE TABLE [member_transaction](
[id] [int] IDENTITY(1,1) NOT NULL,
[member_id] [int] NULL,
[t_type] [varchar](50) NULL,
[debit] [decimal](12, 2) NOT NULL,
[credit] [decimal](12, 2) NOT NULL,
[particular] [varchar](100) NULL,
[remarks] [varchar](150) NULL,
[reference_id] [varchar](50) NULL,
[entry_date] [datetime] NOT NULL,
[is_succeed] [bit] NOT NULL
)
CREATE TABLE [recharge_request](
[id] [bigint] IDENTITY(1,1) NOT NULL,
[mobile_no] [varchar](50) NULL,
[amount] [decimal](12, 0) NULL,
[user_reference_id] [varchar](50) NULL,
[uid] [int] NULL,
[rdate] [datetime] NOT NULL,
[status] [varchar](50) NOT NULL
)
Assuming you're in SQL Server 2012+, you should try something like this:
SELECT
id,
reference_id,
entry_date,
particular,
remarks,
debit,
credit,
sum(isnull(credit,0)-isnull(debit,0)) over (order by entry_date asc) AS balance
FROM
member_transaction a
WHERE
member_id=#mId AND
is_succeed=1 AND
not exist (select 1 FROM recharge_request r WHERE r.user_reference_id = a.reference_id and r.status='Failure')
If you want to fetch more than one member, then you should have partition by in the over part of the sum.
I'm facing a simple problem here that I can't solve, I have this query:
SELECT
MIN(TEA_InicioTarefa),
PFJ_Id_Analista,
ATC_Id,
SRV_Id
FROM
dbo.TarefaEtapaAreaTecnica
INNER JOIN Tarefa t ON t.TRF_Id = TarefaEtapaAreaTecnica.TRF_Id
WHERE SRV_Id = 88
GROUP BY SRV_Id, ATC_Id, PFJ_Id_Analista
ORDER BY ATC_Id ASC
It returns me this:
I was able to group it a little with GROUP BY SRV_Id, ATC_Id, PFJ_Id_Analista that gave me these 8 records, but as you can see some PFJ_Id_Analista are different.
What I want is to select only the early date of each SRV_Id and ATC_Id, the PFJ_Id_Analista don't need to grup, if I remove PFJ_Id_Analista from the grouping the query works, but I need the column.
For eg.: between row number 2 and 3 I want only the early date, so it will be row 2. The same goes for rows 5 to 8, I want only row 6.
DDL for TarefaEtapaAreaTecnica (important key: TRF_Id)
CREATE TABLE [dbo].[TarefaEtapaAreaTecnica](
[TEA_Id] [int] IDENTITY(1,1) NOT NULL,
**[TRF_Id] [int] NOT NULL,**
[ETS_Id] [int] NOT NULL,
[ATC_Id] [int] NOT NULL,
[TEA_Revisao] [int] NOT NULL,
[PFJ_Id_Projetista] [int] NULL,
[TEA_DoctosQtd] [int] NULL,
[TEA_InicioTarefa] [datetime2](7) NULL,
[PFJ_Id_Analista] [int] NULL,
[TEA_FimTarefa] [datetime2](7) NULL,
[TEA_HorasQtd] [numeric](18, 1) NULL,
[TEA_NcfQtd] [int] NULL,
[PAT_Id] [int] NULL
DDL for Tarefa (important keys TRF_Id and SRV_Id (which I need it)):
CREATE TABLE [dbo].[Tarefa](
**[TRF_Id] [int] IDENTITY(1,1) NOT FOR REPLICATION NOT NULL,**
**[SRV_Id] [int] NOT NULL,**
[TRT_Id] [int] NOT NULL,
[TRF_Descr] [varchar](255) NULL,
[TRF_Entrada] [datetime] NOT NULL,
[TRF_DoctosQtd] [int] NOT NULL,
[TRF_Devolucao] [datetime] NULL,
[TRF_NcfQtd] [int] NULL,
[TRF_EhDocInsuf] [bit] NULL,
[TRF_Observ] [varchar](255) NULL,
[TRF_AreasTrfQtd] [int] NULL,
[TRF_AreasTrfLiqQtd] [int] NULL
Thanks a lot.
EDIT:
CORRECT QUERY
Based on #Gordon Linoff post:
select t.TEA_InicioTarefa, t.PFJ_Id_Analista, t.ATC_Id, t.SRV_Id
from (select t.*,
row_number() over (partition by ATC_Id, SRV_Id
order by TEA_InicioTarefa) as seqnum, ta.SRV_Id
from dbo.TarefaEtapaAreaTecnica t
inner join dbo.Tarefa ta on t.TRF_Id = ta.TRF_Id
) t
where seqnum = 1 AND t.SRV_Id = 88
Just use window functions:
select t.*
from (select t.*,
row_number() over (partition by ATC_Id, SRV_Id
order by ini) as seqnum
from dbo.TarefaEtapaAreaTecnica t
) t
where seqnum = 1;
This is really an example of filtering, not aggregation. The problem is getting the right value to filter on.
Then get the grouping first and then do a JOIN with it like
SELECT
x.Min_TEA_InicioTarefa,
t.PFJ_Id_Analista,
t.ATC_Id,
t.SRV_Id
FROM
dbo.TarefaEtapaAreaTecnica t
INNER JOIN Tarefa ta ON ta.TRF_Id = t.TRF_Id
INNER JOIN (
select SRV_Id, MIN(TEA_InicioTarefa) as Min_TEA_InicioTarefa
from dbo.TarefaEtapaAreaTecnica
GROUP BY SRV_Id
) x ON t.SRV_Id = x.SRV_Id
WHERE t.SRV_Id = 88
ORDER BY t.ATC_Id ASC;
I have two tables:
1. TABLE [dbo].[ItemCategories](
[Id] [int] IDENTITY(1,1) NOT NULL,
[CategoryId] [int] NULL,
[StockId] [int] NULL,
2. TABLE [dbo].[Categories](
[Id] [int] IDENTITY(1,1) NOT NULL,
[ParentCategoryId] [int] NULL,
[CategoryName] [nvarchar](100) NULL,
[Slug] [nvarchar](150) NULL
And this query in SQL Server 2012
SELECT [CategoryName], [Slug], [ParentCategoryId], [Id]
FROM [Categories]
ORDER BY [ParentCategoryId] DESC
Which returns these rows
[CategoryName] [Slug] [ParentCategoryId] [Id]
Exercise exercise 42 46
Fashion fashion 42 47
And I have a second query:
SELECT COUNT(*)
FROM [ItemCategories]
WHERE CategoryId = '46' <--- This Id is the same as [Id] from the first query
How can I a modify the first query to add total count from the second query to the returned CategoryName column (as a single string) ?
Like this:
[CategoryName] [Slug] [ParentCategoryId] [Id]
Exercise (31) exercise 42 46
Fashion (56) fashion 42 47
I have created this join, but I don't know how to add the COUNT(*) as text
SELECT [CategoryName], [Slug], [ParentCategoryId], [Categories].[Id]
FROM [Categories]
INNER JOIN [ItemCategories] ON [Categories].[Id]=[ItemCategories].[CategoryId]
ORDER BY [ParentCategoryId] DESC
You can use the count(*) window function. I would put it in a separate column, but you can do:
SELECT [CategoryName] + ' (' + cast(count(*) over (partition by Id) as varchar(255)) + ')',
[Slug], [ParentCategoryId], [Id]
FROM [Categories]
ORDER BY [ParentCategoryId] DESC;
EDIT:
For two tables, use a JOIN and GROUP BY:
SELECT c.CategoryName + ' (' + cast(count(ic.Id) as varchar(255)) + ')',
c.Slug, c.ParentCategoryId, c.Id
FROM Categories c LEFT JOIN
ItemCategories ic
on ic.CategoryId = c.Id
GROUP BY c.CategoryName, c.slug, c.ParentCategoryId, c.id
ORDER BY ParentCategoryId DESC;
I have simple table which puzzles me:
CREATE TABLE [dbo].[T3]
(
[id] [int] IDENTITY(1,1) NOT NULL,
[S_Id] [int] NULL,
[P_Id] [int] NULL,
[level] [int] NULL,
[Path] [nvarchar](255) NULL
) ON [PRIMARY]
In the table is data
id S_Id P_Id level Path
------------------------------------
1 218252 218231 1 218231
2 218271 218252 1 218252
3 218271 218252 2 218231-218252
EDIT:
I try to get the
ID, S_ID, P_ID, level, Path
on maximum length of column Path.
It should return id 3.
If I try to get max len from path like this:
select
b.id, a.p_id, a.s_id,
max(len(a.path)) as Path,
a.path
from
t3 a, t3 b
where
b.id = a.id
group by
a.p_id , a.s_id, b.id , a.path
order by
1
I get all the data, not just row with id 3, why ?
If you only want the max path record... Correct me if I'm wrong.
;WITH tmp AS (select TOP 1 id from #TaskTask3 ORDER BY LEN(path) DESC)
select t.*
from #TaskTask3 t
inner join tmp on tmp.id = t.id
Updates
;WITH tmp AS (select id, row_number() over (partition by S_Id, P_Id order by len(path) DESC) as rn from #TaskTask3)
select t.*
from #TaskTask3 t
inner join tmp on tmp.id = t.id
WHERE tmp.rn = 1
I tried to keep it simple....There are other methods (mentioned already) but I think you need to start slow... :)
declare #maxLen int
select #maxLen = max(len(path))
from t3
select * from t3
where len (path) = #maxLen
To put weePee's answer in a simple way,you can use the following query:
select id,s_id,p_id,level from t3 where len(path)= (select max(len(path)) from t3)
This is what I used to create and insert into table t3:
CREATE TABLE [dbo].[T3]
(
[id] [int] IDENTITY(1,1) NOT NULL,
[S_Id] [int] NULL,
[P_Id] [int] NULL,
[level] [int] NULL,
[Path] [nvarchar](255) NULL
) ON [PRIMARY]
insert into t3 (s_id,p_id,level,path) values (218252,218231,1,'218231'),(218271,218252,1,'218252'),(218271,218252,2,'218231-218252')
I have a table with the following schema
CREATE TABLE [dbo].[personas](
[id_persona] [int] IDENTITY(1,1) NOT NULL,
[nombres] [nvarchar](50) NOT NULL,
[apellido_paterno] [nvarchar](50) NULL,
[apellido_materno] [nvarchar](50) NULL,
[fecha_nacimiento] [date] NOT NULL,
[sexo] [varchar](1) NOT NULL,
[estado_civil] [nvarchar](50) NOT NULL,
[calle] [nvarchar](200) NULL,
[colonia] [nvarchar](100) NULL,
[codigo_postal] [char](5) NOT NULL,
[telefonos] [varchar](50) NULL,
[celular] [varchar](25) NULL,
[email] [varchar](50) NULL,
)
How do I make a query in SQL Server to return rows where nombre, apellido_paterno and apellido_materno are repeated? I mean two or more rows have the same data in these columns.
I suppose I'm looking something opposite to DISTINCT clause
You would want...
SELECT nombre, apellido_paterno, apellido_materno
FROM dbo.personas
GROUP BY nombre, apellido_paterno, apellido_materno
HAVING COUNT(*) > 1
If you want to look at the actual rows, then use that as an inner query and join onto it. So, something like
SELECT *
FROM personas pOuter INNER JOIN
(SELECT nombre, apellido_paterno, apellido_materno
FROM dbo.personas
GROUP BY nombre, apellido_paterno, apellido_materno
HAVING COUNT(*) > 1) pInner
ON pInner.nombre = pOuter.nombre
AND pInner.apellido_paterno = pOuter.apellido_paterno
AND pInner.apellido_materno = pOuter.apellido_materno
;WITH x AS
(
SELECT id_personas, rn = ROW_NUMBER() OVER
(
PARTITION BY nombre, apellido_paterno, apellido_materno
ORDER BY id_personas
)
FROM dbo.personas
)
SELECT <col list>
FROM dbo.personas AS p
WHERE EXISTS
(
SELECT 1 FROM x
WHERE x.id_personas = p.id_personas
AND x.rn > 1
);