SQL query for displaying product sales - sql

I have sales table which consists, ItemSize, GroupName, Quantity, ProductID, etc...
Now I want to display sales according to following format
GroupName ItemSize Quantity ItemSize Quantity
means
BEER 350ml 500 650ml 1000
How I can achieve this in SQL SERVER 2005 EXPRESS (T-SQL)? Thanks
UPDATED:
its my sales table structure
CREATE TABLE [dbo].[SalesLog](
[SalesID] [int] IDENTITY(1,1) NOT NULL,
[MemoNo] [int] NULL,
[ProductCode] [int] NULL,
[Quantity] [int] NULL,
[Price] [int] NULL,
[ProductGroup] [int] NULL,
CONSTRAINT [PK_SalesLog] PRIMARY KEY CLUSTERED
(
[SalesID] ASC
) WITH (PAD_INDEX = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
its my Product table structure
CREATE TABLE [dbo].[Products](
[ProductId] [int] IDENTITY(1,1) NOT NULL,
[pName] [nvarchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
[pSize] [int] NULL,
[pPrice] [int] NULL,
[pPackQty] [int] NULL,
[pGroup] [int] NULL,
[pCode] [int] NULL,
[pStock] [int] NULL,
[pYrStock] [int] NULL,
[pClearStock] [int] NULL,
CONSTRAINT [PK_Products] PRIMARY KEY CLUSTERED
(
[ProductId] ASC
) WITH (PAD_INDEX = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]

You could aggregate the data using SUM and CASE statements.
Using your table definitions (and some very minimal made up data), here is an example of how you could do it:
--** Create test tables
DECLARE #SalesLog TABLE (
SalesID int IDENTITY(1,1) NOT NULL,
MemoNo int NULL,
ProductCode int NULL,
Quantity int NULL,
Price int NULL,
ProductGroup int NULL)
DECLARE #Products TABLE(
ProductId int IDENTITY(1,1) NOT NULL,
pName nvarchar(50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
pSize int NULL,
pPrice int NULL,
pPackQty int NULL,
pGroup int NULL,
pCode int NULL,
pStock int NULL,
pYrStock int NULL,
pClearStock int NULL)
--** Setup test data
INSERT INTO #SalesLog ( MemoNo, ProductCode, Quantity, Price, ProductGroup)
SELECT 0, 1, 500, 0, 1 UNION
SELECT 0, 2, 700, 0, 1 UNION
SELECT 0, 2, 333, 0, 1 UNION
SELECT 0, 3, 200, 0, 2 UNION
SELECT 0, 4, 125, 0, 2 ;
INSERT INTO #Products (pName, pSize, pPrice, pPackQty, pGroup, pCode, pStock, pYrStock, pClearStock)
SELECT 'Beer', 350, 1 , 1, 1, 1, 0, 0, 0 UNION
SELECT 'Beer', 650, 1 , 1, 1, 2, 0, 0, 0 UNION
SELECT 'Beer', 1000, 1 , 1, 1, 3, 0, 0, 0 UNION
SELECT 'Wine', 750, 1 , 1, 2, 4, 0, 0, 0 UNION
SELECT 'Wine', 1000, 1 , 1, 2, 5, 0, 0, 0 ;
--** Example query
SELECT t.pName AS 'Product'
, MAX(CASE WHEN t.Col = 1 THEN t.pSize END) AS 'Item Size'
, ISNULL(SUM(CASE WHEN t.Col = 1 THEN t.Quantity END),0) AS 'Quantity'
, MAX(CASE WHEN t.Col = 2 THEN t.pSize END) AS 'Item Size'
, ISNULL(SUM(CASE WHEN t.Col = 2 THEN t.Quantity END),0) AS 'Quantity'
, MAX(CASE WHEN t.Col = 3 THEN t.pSize END) AS 'Item Size'
, ISNULL(SUM(CASE WHEN t.Col = 3 THEN t.Quantity END),0) AS 'Quantity'
FROM (
SELECT pName
, pCode
, pGroup
, pSize
, sl.Quantity
, DENSE_RANK() OVER(PARTITION BY p.pGroup ORDER BY p.pSize) AS Col
FROM #Products AS p
LEFT JOIN #SalesLog AS sl
ON p.pGroup = sl.ProductGroup
AND p.pCode = sl.ProductCode
) AS t
GROUP BY t.pGroup
, t.pName
;
The query uses the DENSE_RANK function to group items of a size together and to order them in assending order of size and this is used to work out which column the data should be written to.
Although there is a PIVOT operator in SQL Server 2005 and above, it isn't very helpful when you have different column heading types (item size and quantity in this case).
You will have to decide on the maximum number of product sizes that you want to report on as this is hard coded into the query. So if the maximum number of product sizes is 3 then you code the query as shown above. If, however, one of your products has 4 different sizes, then you are going to add an additional Item Size and Quantity pair of columns for t.Col = 4 and so on.
I hope this helps.

It looks like you are trying to do a PIVOT table, where the different item sizes are represented as different columns rather than rows. Take a look at http://msdn.microsoft.com/en-us/library/ms177410.aspx

Related

How to optimize sql multiple select queries?

I have a query that calculates wait time for each record from the Transactions table and calculates SUM and MAX wait time for each of the group below based on receivedDate and claimedDt.
Here is a basic query:
SELECT
'2022-06-01' as reportDate,
waitTimeSubQuery.currentAssignedQueueId,
waitTimeSubQuery.queueAccessPointId,
waitTimeSubQuery.queueName AS QueueName,
waitTimeSubQuery.queueReportCategory,
waitTimeSubQuery.queuePriority,
waitTimeSubQuery.queueOrganizationHierarchyId,
COUNT(waitTimeSubQuery.id) AS totalCasesWaiting,
SUM(CASE WHEN waitTimeSubQuery.waitTimeMinutes > 0 THEN waitTimeSubQuery.waitTimeMinutes ELSE 0 END) AS sumWaitTimeMinutes,
MAX(CASE WHEN waitTimeSubQuery.waitTimeMinutes > 0 THEN waitTimeSubQuery.waitTimeMinutes ELSE 0 END) AS maxWaitTimeMinutes
FROM (SELECT
id,
currentAssignedQueueId,
queueAccessPointId,
queueName,
queueReportCategory,
queuePriority,
queueOrganizationHierarchyId,
(CASE WHEN (receivedDateUTC > '0001-01-01T00:00:00Z' OR receivedDate > '0001-01-01T00:00:00Z') AND (appointmentDT IS NULL OR appointmentDT < '2022-09-28T12:58:47')
THEN CAST(DateDiff(MINUTE,
CASE WHEN receivedDateUTC > '0001-01-01T00:00:00Z'
THEN CONCAT(SUBSTRING(CAST(receivedDateUTC AS VARCHAR), 0, 19), 'Z')
ELSE TRY_CAST(CONCAT(CONCAT(SUBSTRING(CAST(receivedDate AS VARCHAR), 0, 10), SUBSTRING(CAST(createdDT AS VARCHAR), 10, 9)), 'Z') AS DATETIME2) END,
CASE WHEN claimedDT > '0001-01-01T00:00:00Z' AND claimedDT < '2022-06-01T23:59:00Z' AND transactionStatus != 'WaitingAssignment'
THEN CONCAT(SUBSTRING(CAST(claimedDT AS VARCHAR), 0, 19), 'Z')
ELSE '2022-06-01T23:59:00Z' END
) AS BIGINT)
ELSE 0 END) AS waitTimeMinutes
FROM #transactionsList
WHERE receivedDate <= '2022-06-01T00:00:00'
AND (claimedDT >= '2022-06-02T00:00:00' OR transactionStatus = 'WaitingAssignment')) waitTimeSubQuery
GROUP BY waitTimeSubQuery.currentAssignedQueueId,
waitTimeSubQuery.queueAccessPointId,
waitTimeSubQuery.queueName,
waitTimeSubQuery.queueReportCategory,
waitTimeSubQuery.queuePriority,
waitTimeSubQuery.queueOrganizationHierarchyId
I want to calculate statistics for each day for the period of 30 days and the only difference is dates used for calculating waitTimeMinutes (based on endDate, claimedDt, receivedDate) and filtering by receivedDate and claimedDt.
I tried to save sub-set of the Transactions data into a table variable and reuse it in multiple select queries to get the statistics for each day, but this script runs too slow
Here is the code:
DECLARE #transactionsList TABLE (
id UNIQUEIDENTIFIER,
currentAssignedQueueId UNIQUEIDENTIFIER,
queueAccessPointId UNIQUEIDENTIFIER,
queueName VARCHAR(100),
queueReportCategory VARCHAR(100),
queuePriority INT,
queueOrganizationHierarchyId UNIQUEIDENTIFIER,
receivedDate DATE,
claimedDT DATE,
transactionStatus VARCHAR(100),
receivedDateUTC DATE,
appointmentDT DATE,
createdDT DATE)
INSERT INTO #transactionsList
SELECT
Transactions.id,
Transactions.currentAssignedQueueId,
Queues.accessPointId as queueAccessPointId,
Queues.name as queueName,
Queues.reportCategory as queueReportCategory,
Queues.priority as queuePriority,
Queues.organizationHierarchyId as queueOrganizationHierarchyId,
Transactions.receivedDate,
Transactions.claimedDT,
Transactions.transactionStatus,
Transactions.receivedDateUTC,
Transactions.appointmentDT,
Transactions.createdDT
FROM Transactions
LEFT JOIN Queues ON Transactions.currentAssignedQueueId = Queues.Id
WHERE Transactions.consumerId = '66458f4a-b3d4-4f80-93d4-5aa3ea123249'
AND Transactions.isActive = 1
AND Transactions.receivedDate <= '2022-06-30T00:00:00'
AND (Transactions.claimedDT >= '2022-06-02T00:00:00' OR Transactions.transactionStatus = 'WaitingAssignment')
--SELECT COUNT(*) FROM #transactionsList
-- 2022-06-01
SELECT
'2022-06-01' as reportDate,
waitTimeSubQuery.currentAssignedQueueId,
waitTimeSubQuery.queueAccessPointId,
waitTimeSubQuery.queueName AS QueueName,
waitTimeSubQuery.queueReportCategory,
waitTimeSubQuery.queuePriority,
waitTimeSubQuery.queueOrganizationHierarchyId,
COUNT(waitTimeSubQuery.id) AS totalCasesWaiting,
SUM(CASE WHEN waitTimeSubQuery.waitTimeMinutes > 0 THEN waitTimeSubQuery.waitTimeMinutes ELSE 0 END) AS sumWaitTimeMinutes,
MAX(CASE WHEN waitTimeSubQuery.waitTimeMinutes > 0 THEN waitTimeSubQuery.waitTimeMinutes ELSE 0 END) AS maxWaitTimeMinutes
FROM (SELECT
id,
currentAssignedQueueId,
queueAccessPointId,
queueName,
queueReportCategory,
queuePriority,
queueOrganizationHierarchyId,
(CASE WHEN (receivedDateUTC > '0001-01-01T00:00:00Z' OR receivedDate > '0001-01-01T00:00:00Z') AND (appointmentDT IS NULL OR appointmentDT < '2022-09-28T12:58:47')
THEN CAST(DateDiff(MINUTE,
CASE WHEN receivedDateUTC > '0001-01-01T00:00:00Z'
THEN CONCAT(SUBSTRING(CAST(receivedDateUTC AS VARCHAR), 0, 19), 'Z')
ELSE TRY_CAST(CONCAT(CONCAT(SUBSTRING(CAST(receivedDate AS VARCHAR), 0, 10), SUBSTRING(CAST(createdDT AS VARCHAR), 10, 9)), 'Z') AS DATETIME2) END,
CASE WHEN claimedDT > '0001-01-01T00:00:00Z' AND claimedDT < '2022-06-01T23:59:00Z' AND transactionStatus != 'WaitingAssignment'
THEN CONCAT(SUBSTRING(CAST(claimedDT AS VARCHAR), 0, 19), 'Z')
ELSE '2022-06-01T23:59:00Z' END
) AS BIGINT)
ELSE 0 END) AS waitTimeMinutes
FROM #transactionsList
WHERE receivedDate <= '2022-06-01T00:00:00'
AND (claimedDT >= '2022-06-02T00:00:00' OR transactionStatus = 'WaitingAssignment')) waitTimeSubQuery
GROUP BY waitTimeSubQuery.currentAssignedQueueId,
waitTimeSubQuery.queueAccessPointId,
waitTimeSubQuery.queueName,
waitTimeSubQuery.queueReportCategory,
waitTimeSubQuery.queuePriority,
waitTimeSubQuery.queueOrganizationHierarchyId
And the part from '2022-06-01' repeats 30 times for each day from the range respectively.
Is there any possibility to optimize this script? For my data it runs nearly 49 seconds and the number of the records in the table is only 7kk and it's far way more on other environment.
---EDIT---
Here are the definitions for the tables Transactions and Queues
CREATE TABLE [dbo].[Transactions] (
[id] UNIQUEIDENTIFIER NULL,
[accessPointId] UNIQUEIDENTIFIER NULL,
[isNonLobby] BIT NULL,
[printReceipt] BIT NULL,
[isExpressed] BIT NULL,
[isAssignedBySupervisor] BIT NULL,
[dateAssignedBySupervisor] VARCHAR (30) NULL,
[dateAssignedBySupervisorLocal] DATETIMEOFFSET (7) NULL,
[supervisorOverrideId] UNIQUEIDENTIFIER NULL,
[supervisorId] UNIQUEIDENTIFIER NULL,
[isNewHousehold] BIT NULL,
[householdId] UNIQUEIDENTIFIER NULL,
[receivedDate] DATE NULL,
[receivedDateUTC] DATETIME2 (7) NULL,
[transactionStatus] VARCHAR (20) NULL,
[claimedDT] DATETIME2 (7) NULL,
[claimedDTLocal] DATE NULL,
[initiallyClaimedById] UNIQUEIDENTIFIER NULL,
[completedDT] DATETIME2 (7) NULL,
[appointmentDT] DATETIME2 (7) NULL,
[completedDTLocal] DATE NULL,
[completedById] UNIQUEIDENTIFIER NULL,
[remarks] VARCHAR (MAX) NULL,
[currentAssignedQueueId] UNIQUEIDENTIFIER NULL,
[currentAssignedUserId] UNIQUEIDENTIFIER NULL,
[preTriageTransactionId] UNIQUEIDENTIFIER NULL,
[isAddClaim] BIT NULL,
[receiptId] UNIQUEIDENTIFIER NULL,
[ticketNumber] VARCHAR (100) NULL,
[deliNumber] VARCHAR (100) NULL,
[tasksCount] BIGINT NULL,
[projectedWaitTime] BIGINT NULL,
[actualWaitTimeMinutes] BIGINT NULL,
[assignWaitTime] BIGINT NULL,
[transactionTimeMinutes] BIGINT NULL,
[triageTimeMinutes] BIGINT NULL,
[outcomeId] UNIQUEIDENTIFIER NULL,
[outcomeReasonId] UNIQUEIDENTIFIER NULL,
[outcomeType] VARCHAR (50) NULL,
[dueDate] VARCHAR (30) NULL,
[dueDateLocal] DATETIMEOFFSET (7) NULL,
[isDueDateToday] VARCHAR (30) NULL,
[isUnknownHousehold] BIT NULL,
[activityId] UNIQUEIDENTIFIER NULL,
[programId] UNIQUEIDENTIFIER NULL,
[reviewMonthDueDate] VARCHAR (40) NULL,
[reviewMonthDueDateLocal] DATETIMEOFFSET (7) NULL,
[officeId] UNIQUEIDENTIFIER NULL,
[isOnceManuallyPaused] BIT NULL,
[pkey] VARCHAR (100) NULL,
[isActive] BIT NULL,
[consumerId] UNIQUEIDENTIFIER NULL,
[organizationName] VARCHAR (50) NULL,
[modifiedBy] UNIQUEIDENTIFIER NULL,
[modifiedDT] DATETIME2 (7) NULL,
[modifiedDTLocal] DATE NULL,
[createdBy] UNIQUEIDENTIFIER NULL,
[createdDT] DATETIME2 (7) NULL,
[createdDTLocal] DATE NULL,
[_ts] BIGINT NULL,
[type] VARCHAR (50) NULL,
[timezoneId] VARCHAR (50) NULL
);
CREATE TABLE [dbo].[Queues] (
[id] UNIQUEIDENTIFIER NULL,
[name] VARCHAR (255) NULL,
[accessPointId] UNIQUEIDENTIFIER NULL,
[organizationHierarchyId] UNIQUEIDENTIFIER NULL,
[assignedOrganizationHierarchyLevel] VARCHAR (20) NULL,
[bundlingGroup] BIGINT NULL,
[reportCategory] VARCHAR (100) NULL,
[priority] INT NULL,
[businessProcessThreshold] BIGINT NULL,
[calculateProjectedWaitTime] BIT NULL,
[waitTimeUnits] VARCHAR (10) NULL,
[hasCarryOver] BIT NULL,
[defaultTransactionTimeMinutes] BIGINT NULL,
[latestQueueMetricId] UNIQUEIDENTIFIER NULL,
[isAppointment] BIT NULL,
[consumerId] UNIQUEIDENTIFIER NULL,
[organizationName] VARCHAR (50) NULL,
[modifiedBy] UNIQUEIDENTIFIER NULL,
[modifiedDT] DATE NULL,
[createdBy] UNIQUEIDENTIFIER NULL,
[createdDT] DATE NULL,
[_ts] BIGINT NULL
);
And an index for the Transactions table (this is the only one index for this table and there are no indexes for the Queues table):
CREATE NONCLUSTERED INDEX [nci_wi_Transactions_EBAFDE3A7C2969265E76135FBA69188D] ON [dbo].[Transactions]
(
[consumerId] ASC,
[isActive] ASC,
[receivedDate] ASC
)
INCLUDE([appointmentDT],[claimedDT],[createdDT],[currentAssignedQueueId],[id],[receivedDateUTC],[transactionStatus]) WITH (STATISTICS_NORECOMPUTE = OFF, DROP_EXISTING = OFF, ONLINE = OFF, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
GO
Here is the link on GitHub for the execution plan and the full query
https://github.com/sskotliar/query_optimization
PasteThePlan link
Option - 1
You can improve the performance of your query by using a CTE. How does CTE work? The query you write inside the WITH command is executed only once, and its result is stored as a temporary table. This allows you to execute your large query with multiple join in it once. In the remaining cases, only its result is used. But as I understood you call your query with different filters. If this is true, so please see Option 2.
Option - 2
If the result of your repeatable query is large, and you call this query with different filters, it is recommended that you, insert result of repeatable query into temp table, then create needed indexes for this temp table. Then you can use that table as much as you need. Since your table has indexes so your filters will be works high performance.
For each of the options mentioned above, it is recommended that you view Query Plan. Because the query plan may change from the DB side depending on the count of records in the tables.

SQL Server CTE Hierarchy query aggregation

I want to calculate SUM of all children with CTE here is DDL/DML. 0 values are which I don't know and to be calculated through aggregation
CREATE TABLE [dbo].[Product]
(
[ID] [INT] IDENTITY(1,1) NOT NULL,
[Hierarchy] [VARCHAR](100) NOT NULL,
[ParentID] [INT] NULL,
[SalesAmount] [INT] NULL
) ON [PRIMARY]
GO
SET IDENTITY_INSERT [dbo].[Product] ON
GO
INSERT [dbo].[Product] ([ID], [Hierarchy], [ParentID], [SalesAmount])
VALUES (1, N'root', NULL, 0),
(2, N'T1', 1, 0),
(3, N'T2', 1, 0),
(4, N'C1', 2, 0),
(5, N'C2', 3, 0),
(6, N'C3', 2, 0),
(7, N'P1', 4, 1000),
(8, N'P2', 5, 2000),
(9, N'P3', 6, 3000)
I tried below query and it gives me following output,
WITH CT AS
(
SELECT
ID, Hierarchy, ParentID, 0 AS Level,
CAST ([Hierarchy] AS VARCHAR (MAX)) AS [Linkeage]
FROM
dbo.Product
WHERE
ParentID IS NULL
UNION ALL
SELECT
pc.ID, pc.Hierarchy, pc.ParentID, p1.Level + 1,
p1.Linkeage + ' -> ' + CAST ([pc].[Hierarchy] AS VARCHAR (MAX))
FROM
dbo.Product AS pc
JOIN
CT AS p1 ON p1.ID = pc.ParentID
),
Aggr AS
(
SELECT
TC.ParentID,
SUM(T.SalesAmount) AS sum_TotalAmt
FROM
CT TC
INNER JOIN
Product AS T ON TC.ID = T.ID
GROUP BY
TC.ParentID
)
SELECT
ID, Hierarchy, T.ParentID, Level, Linkeage, A.sum_TotalAmt
FROM
CT AS T
LEFT JOIN
Aggr AS A ON ISNULL(T.Id, T.ParentID) = A.ParentID
I need existing output + underlined rows as well.
I figured out by my-self by in different approach, i wanted to get aggregates of multiple group by values,
CREATE TABLE [dbo].[Product](
[ProductID] [int] IDENTITY(1,1) NOT NULL,
[ProductType] [varchar](100) NOT NULL,
[ProductCategory] [varchar](100) NOT NULL,
[ProductName] [varchar](100) NOT NULL,
[SalesAmount] [decimal]
) ON [PRIMARY]
So i can simply get output with below
select [ProductType], [ProductCategory], SUM( [SalesAmount] ) as TotalSales
from Product
GROUP BY ROLLUP (ProductType,ProductCategory)

How to get second lowest cost SQL

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.

Select Sublist Quantity from Table in SQL Server

I am working with SQL sever table and at technical point I am stuck.
Below I am attaching a screen-shot of the table query and result also the required logic.
There are two portions of query, one is without any condition and second is with condition that select "qty" when parent_id is NULL else print 0,
I want to print the "qty" of sub-item when its qty differs from its parent's "qty"
Here is the script:
GO
CREATE TABLE [dbo].[#Temp_order](
[order_id] [int] IDENTITY(1,1) NOT NULL,
[orderdate] [datetime] NULL
) ON [PRIMARY]
GO
GO
CREATE TABLE [dbo].[#Temp_order_list](
[order_list_id] [int] IDENTITY(1,1) NOT NULL,
[order_id] [int] NOT NULL,
[qty] [int] NOT NULL,
[price] [money] NOT NULL,
[type] [int] NOT NULL,
[parent_id] [int] NULL,
CONSTRAINT [PK_Temp_order_list] PRIMARY KEY CLUSTERED
(
[order_list_id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
/*
*/
INSERT INTO #Temp_order
( orderdate )
VALUES ( '2015-01-16 05:08:53' -- orderdate - datetime
)
INSERT INTO #Temp_order_list
( order_id, qty, price, type, parent_id )
VALUES ( (SELECT MAX(order_id) FROM #Temp_order), -- order_id - int
1, -- qty - int
10, -- price - money
2, -- type - int
NULL -- parent_id - int
)
DECLARE #ParentID AS INTEGER
SELECT #ParentID = MAX(order_list_id) FROM #Temp_order_list
INSERT INTO #Temp_order_list
( order_id, qty, price, type, parent_id )
VALUES ( (SELECT MAX(order_id) FROM #Temp_order), -- order_id - int
1, -- qty - int
12, -- price - money
3, -- type - int
#ParentID -- parent_id - int
)
INSERT INTO #Temp_order_list
( order_id, qty, price, type, parent_id )
VALUES ( (SELECT MAX(order_id) FROM #Temp_order), -- order_id - int
4, -- qty - int
13, -- price - money
3, -- type - int
#ParentID -- parent_id - int
)
SELECT * FROM #Temp_order_list WHERE order_id = 1
SELECT #Temp_order.order_id ,#Temp_order_list.order_list_id,#Temp_order_list.price,#Temp_order_list.type,
CASE WHEN #Temp_order_list.parent_id IS NOT NULL THEN 0
ELSE
ISNULL(#Temp_order_list.qty ,'') END AS quantity
FROM #Temp_order
INNER JOIN #Temp_order_list ON #Temp_order.order_id = #Temp_order_list.order_id
WHERE #Temp_order.order_id = 1
DROP TABLE #Temp_order
DROP TABLE #Temp_order_list
Any better solution?
Looking at your last comment, I can suggest to add self join and check that condition :
SELECT ordr.order_id,
list.order_list_id,
list.price,
list.type,
CASE
WHEN parentlist.order_list_id IS NOT NULL THEN list.qty
WHEN list.parent_id IS NOT NULL THEN 0
ELSE ISNULL(list.qty, '')
END AS quantity
FROM #Temp_order ordr
INNER JOIN #Temp_order_list list
ON ordr.order_id = list.order_id
LEFT JOIN #Temp_order_list parentlist
ON parentlist.order_list_id = list.parent_id
AND list.qty > parentlist.qty
AND list.type = 3
WHERE ordr.order_id = 1

Customer can only have 01 orderOnSale subquery / CROSS APPLY in SQL Server 2008

I have created a dummy scenario that reflect many of the queries I have to write to check that some data we are importing is correct.
The example would be when you have 3 tables
Store
Customer
CustomerOrder
A Customer can belong to many stores but can only 1 OrderOnsale can be bought x customer x store.
Cannot seem to get it right. Below is tables and noddy data + my attempt.
IF object_id(N'Store', 'U') IS NOT NULL
DROP TABLE Store
GO
CREATE TABLE [dbo].[Store]
(
[Id] [bigint] NOT NULL,
[StoreName] [varchar](50) NOT NULL,
CONSTRAINT [PK_Store] PRIMARY KEY CLUSTERED ([Id] ASC)
) ON [PRIMARY]
GO
IF object_id(N'Customer', 'U') IS NOT NULL
DROP TABLE Customer
GO
CREATE TABLE [dbo].[Customer]
(
[CustomerId] [bigint] NOT NULL,
[StoreId] [bigint] NOT NULL,
[Name] [varchar](50) NOT NULL,
[Surname] [varchar](50) NOT NULL,
CONSTRAINT [PK_Customer] PRIMARY KEY CLUSTERED ([CustomerId] ASC)
) ON [PRIMARY]
GO
IF object_id(N'CustomerOrder', 'U') IS NOT NULL
DROP TABLE CustomerOrder
GO
CREATE TABLE [dbo].[CustomerOrder]
(
[OrderId] [bigint] NOT NULL,
[CustomerId] [bigint] NOT NULL,
[OrderName] [varchar](50) NOT NULL,
[OnSale] [bit] NOT NULL,
CONSTRAINT [PK_CustomerOrder] PRIMARY KEY CLUSTERED([OrderId] ASC)
) ON [PRIMARY]
GO
begin tran
INSERT INTO [dbo].[Store]([Id], [StoreName])
SELECT 1, N'Harrods' UNION ALL
SELECT 2, N'John Lewis'
INSERT INTO [dbo].[Customer]([CustomerId], [StoreId], [Name], [Surname])
SELECT 1, 1, N'John', N'Smith' UNION ALL
SELECT 2, 2, N'Joe', N'Blogg'
INSERT INTO [dbo].[CustomerOrder]([OrderId], [CustomerId], [OrderName], [OnSale])
SELECT 1, 1, N'Toys', 1 UNION ALL
SELECT 2, 1, N'Laptop', 1 UNION ALL
SELECT 3, 2, N'Toys', 0
commit
My incomplete attempt:
SELECT
HasCustomerBoughtMoreThanO1ItemOnSale =
CASE WHEN Count(T2.TotalBoughtOnSale) > 1 THEN 1 ELSE 0 END
FROM
CustomerOrder co1
INNER JOIN
customer c1 ON co1.CustomerId = c1.CustomerId
INNER JOIN
STORE S01 ON C1.StoreId = S01.Id
JOIN
(SELECT
CO2.CustomerId, S2.Id AS StoreId,
Count(CO2.OnSale) TotalBoughtOnSale
FROM
CustomerOrder CO2
INNER JOIN
customer c2 ON c2.CustomerId = CO2.CustomerId
INNER JOIN
STORE S2 ON C2.StoreId = S2.Id
WHERE
CO2.OnSale = 1
GROUP BY
CO2.CustomerId, S2.Id) AS t2 ON c1.CustomerId = T2.CustomerId
AND S01.Id = t2.StoreId
If what your after is if a single customer has bought more then one OnSale item then this query will do the trick.
SELECT
CO.CustomerId, C.StoreId
FROM CustomerOrder CO
INNER JOIN Customer C ON CO.CustomerId = C.CustomerId
WHERE OnSale = 1
GROUP BY CO.CustomerId, C.StoreId
HAVING COUNT(*) > 1
I should add that in this its given that a Customer can only shop in a single Store due to StoreId is a column in the Customer table.