I have a series of Receive and Issue transactions. Received inventory can be at different costs per job material item, possibly received in multiple transactions. And there are two possible methods of receipt: Mfg Receipt and Receipt Lines. Where neither exist, the cost defaults to average inventory cost, which is reliably stored in Cost Type. Received cost is not reliably stored in an Issue transaction's Cost Type, so I have to search backward in the receipt transactions. This precedence is handled by COALESCE.
The aim is to return (reverse) issue to inventory at the same cost at which it was received. Subsequent receipts are possible, at a different cost, and returns should be at that cost, and not at costs from receipts prior or subsequent within the same job.
Transaction (prefix imt) joined to Cost Type (prefix int) look like this for Material ID 21:
Each MaterialIssue transactions can pair to each Receipt Lines, so I have to restrict the inner result to a single receive transaction to prevent Cartesian product, without which, I could get multiple results, as in material item 21:
I have tried to accomplish with this CTE, using ROW() ranking, commented with the imaginary desired method, but it's mind-bending and I'm not sure how to go about it:
DECLARE #bShowNonInventory BIT = 1
DECLARE #nCostingMethod INT = 1
DECLARE #vJobID VARCHAR (11) = '23532-02-01'
; WITH
MaterialIssues as (
SELECT
MI.imtJobID JobID
, MI.imtJobAssemblyID AssemblyID
, MI.imtJobMaterialID MaterialID
, SUM(
(
COALESCE(
MR.intActualUnitMaterialCost
, RL.intActualUnitMaterialCost
, intUnitMaterialCost
)
)
* - (intQuantity)
) NetCost
FROM PartTransactions MI -- Material Issue
INNER JOIN PartTransactionCosts
ON imtPartTransactionID = intPartTransactionID
LEFT JOIN /* get single, most recent received cost */
( SELECT * FROM
(
SELECT
imtJobID, imtJobAssemblyID, imtJobMaterialID
, imtPartTransactionID
, intActualUnitMaterialCost
, ROW_Number()
OVER (Partition by imtJobID, imtJobAssemblyID, imtJobMaterialID
Order by imtPartTransactionID DESC) as rn
--^ set of results from ranking too broad
FROM PartTransactionCosts
JOIN PartTransactions
on imtPartTransactionID=intPartTransactionID
WHERE imtTableName='MfgReceipts'
AND intCostType = 4
--< need outer reference here somehow: imtPartTransactionID < (earlier) MI.imtPartTransactionID
) as d
WHERE rn=1
) MR -- Receipt by Mfg Receipt
ON MI.imtJobID=MR.imtJobID
AND MI.imtJobAssemblyID=MR.imtJobAssemblyID
AND MI.imtJobMaterialID=MR.imtJobMaterialID
AND MR.imtPartTransactionID < MI.imtPartTransactionID --< dubious restriction on inner result
LEFT JOIN
( SELECT * FROM
(
SELECT imtJobID, imtJobAssemblyID, imtJobMaterialID
, intActualUnitMaterialCost, imtPartTransactionID
, ROW_Number()
OVER (Partition by imtJobID, imtJobAssemblyID, imtJobMaterialID
Order by imtPartTransactionID DESC) as rn
FROM PartTransactionCosts
JOIN PartTransactions
on imtPartTransactionID=intPartTransactionID
WHERE imtTableName='ReceiptLines'
AND intCostType = 4
--< need outer reference here somehow: imtPartTransactionID < (earlier) MI.imtPartTransactionID
) as d
WHERE rn=1
) RL -- Receipt by ReceiptLine
ON MI.imtJobID=RL.imtJobID
AND MI.imtJobAssemblyID=RL.imtJobAssemblyID
AND MI.imtJobMaterialID=RL.imtJobMaterialID
AND RL.imtPartTransactionID < MI.imtPartTransactionID --< dubious restriction on inner result
WHERE
imtSource = 3
AND imtNonInventoryTransaction <= #bShowNonInventory
AND intCostType = #nCostingMethod
GROUP BY MI.imtJobID
, MI.imtJobAssemblyID
, MI.imtJobMaterialID
)
-- test query:
Select * from
MaterialIssues
WHERE JobID = #vJobID
Note that this problem is very similar to Restricting inner query with outer query atttribute - but I don't see a requirement to restrict the inner set to one, most recent, but not subsequent result.
In summary, the net result of quantities received and (return) issued for item 21 is zero, but the net cost should also be zero, but is not correct.
Thank you in advance for your suggestions.
EDIT: DDL and sample data:
USE [master]
GO
CREATE DATABASE [test]
CONTAINMENT = NONE
ON PRIMARY
( NAME = N'test', FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL12.MSSQLSERVER\MSSQL\DATA\test.mdf' , SIZE = 3072KB , MAXSIZE = UNLIMITED, FILEGROWTH = 1024KB )
LOG ON
( NAME = N'test_log', FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL12.MSSQLSERVER\MSSQL\DATA\test_log.ldf' , SIZE = 199680KB , MAXSIZE = 2048GB , FILEGROWTH = 10%)
GO
USE test
CREATE TABLE [test].dbo.[PartTransactions](
[imtPartTransactionID] [int] NOT NULL,
[imtTableName] [nvarchar](30) NOT NULL,
[imtTransactionType] [tinyint] NOT NULL,
[imtSource] [tinyint] NOT NULL,
[imtNonInventoryTransaction] [bit] NOT NULL,
[imtJobID] [nvarchar](20) NOT NULL,
[imtJobAssemblyID] [int] NOT NULL,
[imtJobMaterialID] [int] NOT NULL,
[imtPartID] [nvarchar](30) NOT NULL,
) ON [PRIMARY]
GO
CREATE TABLE [test].[dbo].[PartTransactionCosts](
[intPartTransactionID] [int] NOT NULL,
[intPartTransactionCostID] [int] NOT NULL,
[intCostType] [tinyint] NOT NULL,
[intQuantity] [numeric](15, 5) NOT NULL,
[intUnitMaterialCost] [numeric](15, 5) NOT NULL,
[intActualUnitMaterialCost] [numeric](15, 5) NOT NULL,
) ON [PRIMARY]
GO
-- USE [test]
GO
INSERT [dbo].[PartTransactions] ([imtPartTransactionID], [imtTableName], [imtTransactionType], [imtSource], [imtNonInventoryTransaction], [imtJobID], [imtJobAssemblyID], [imtJobMaterialID], [imtPartID]) VALUES (117718, N'MaterialIssueLines', 2, 3, 0, N'23532-02-01', 0, 21, N'26271/2GC')
GO
INSERT [dbo].[PartTransactions] ([imtPartTransactionID], [imtTableName], [imtTransactionType], [imtSource], [imtNonInventoryTransaction], [imtJobID], [imtJobAssemblyID], [imtJobMaterialID], [imtPartID]) VALUES (117719, N'MfgReceipts', 1, 2, 1, N'23532-02-01', 0, 21, N'26271/2GC')
GO
INSERT [dbo].[PartTransactions] ([imtPartTransactionID], [imtTableName], [imtTransactionType], [imtSource], [imtNonInventoryTransaction], [imtJobID], [imtJobAssemblyID], [imtJobMaterialID], [imtPartID]) VALUES (117726, N'MaterialIssueLines', 2, 3, 0, N'23532-02-01', 0, 21, N'26271/2GC')
GO
INSERT [dbo].[PartTransactions] ([imtPartTransactionID], [imtTableName], [imtTransactionType], [imtSource], [imtNonInventoryTransaction], [imtJobID], [imtJobAssemblyID], [imtJobMaterialID], [imtPartID]) VALUES (117725, N'MfgReceipts', 1, 2, 1, N'23532-02-01', 0, 21, N'26271/2GC')
GO
INSERT [dbo].[PartTransactions] ([imtPartTransactionID], [imtTableName], [imtTransactionType], [imtSource], [imtNonInventoryTransaction], [imtJobID], [imtJobAssemblyID], [imtJobMaterialID], [imtPartID]) VALUES (117727, N'MaterialIssueLines', 2, 3, 0, N'23532-02-01', 0, 21, N'26271/2GC')
GO
INSERT [dbo].[PartTransactions] ([imtPartTransactionID], [imtTableName], [imtTransactionType], [imtSource], [imtNonInventoryTransaction], [imtJobID], [imtJobAssemblyID], [imtJobMaterialID], [imtPartID]) VALUES (117513, N'MfgReceipts', 1, 2, 1, N'23532-02-01', 0, 21, N'26271/2GC')
GO
INSERT [dbo].[PartTransactionCosts] ([intPartTransactionID], [intPartTransactionCostID], [intCostType], [intQuantity], [intUnitMaterialCost], [intActualUnitMaterialCost]) VALUES (117718, 1, 1, CAST(555.00000 AS Numeric(15, 5)), CAST(1.61513 AS Numeric(15, 5)), CAST(1.61513 AS Numeric(15, 5)))
GO
INSERT [dbo].[PartTransactionCosts] ([intPartTransactionID], [intPartTransactionCostID], [intCostType], [intQuantity], [intUnitMaterialCost], [intActualUnitMaterialCost]) VALUES (117718, 2, 2, CAST(555.00000 AS Numeric(15, 5)), CAST(1.53503 AS Numeric(15, 5)), CAST(1.53503 AS Numeric(15, 5)))
GO
INSERT [dbo].[PartTransactionCosts] ([intPartTransactionID], [intPartTransactionCostID], [intCostType], [intQuantity], [intUnitMaterialCost], [intActualUnitMaterialCost]) VALUES (117718, 3, 3, CAST(555.00000 AS Numeric(15, 5)), CAST(0.00000 AS Numeric(15, 5)), CAST(0.00000 AS Numeric(15, 5)))
GO
INSERT [dbo].[PartTransactionCosts] ([intPartTransactionID], [intPartTransactionCostID], [intCostType], [intQuantity], [intUnitMaterialCost], [intActualUnitMaterialCost]) VALUES (117718, 4, 4, CAST(555.00000 AS Numeric(15, 5)), CAST(1.24865 AS Numeric(15, 5)), CAST(1.24865 AS Numeric(15, 5)))
GO
INSERT [dbo].[PartTransactionCosts] ([intPartTransactionID], [intPartTransactionCostID], [intCostType], [intQuantity], [intUnitMaterialCost], [intActualUnitMaterialCost]) VALUES (117719, 1, 1, CAST(555.00000 AS Numeric(15, 5)), CAST(1.61513 AS Numeric(15, 5)), CAST(1.61513 AS Numeric(15, 5)))
GO
INSERT [dbo].[PartTransactionCosts] ([intPartTransactionID], [intPartTransactionCostID], [intCostType], [intQuantity], [intUnitMaterialCost], [intActualUnitMaterialCost]) VALUES (117719, 2, 2, CAST(555.00000 AS Numeric(15, 5)), CAST(1.53503 AS Numeric(15, 5)), CAST(1.53503 AS Numeric(15, 5)))
GO
INSERT [dbo].[PartTransactionCosts] ([intPartTransactionID], [intPartTransactionCostID], [intCostType], [intQuantity], [intUnitMaterialCost], [intActualUnitMaterialCost]) VALUES (117719, 3, 3, CAST(555.00000 AS Numeric(15, 5)), CAST(0.00000 AS Numeric(15, 5)), CAST(0.00000 AS Numeric(15, 5)))
GO
INSERT [dbo].[PartTransactionCosts] ([intPartTransactionID], [intPartTransactionCostID], [intCostType], [intQuantity], [intUnitMaterialCost], [intActualUnitMaterialCost]) VALUES (117719, 4, 4, CAST(555.00000 AS Numeric(15, 5)), CAST(1.16410 AS Numeric(15, 5)), CAST(1.16410 AS Numeric(15, 5)))
GO
INSERT [dbo].[PartTransactionCosts] ([intPartTransactionID], [intPartTransactionCostID], [intCostType], [intQuantity], [intUnitMaterialCost], [intActualUnitMaterialCost]) VALUES (117726, 1, 1, CAST(1100.00000 AS Numeric(15, 5)), CAST(1.61513 AS Numeric(15, 5)), CAST(1.61513 AS Numeric(15, 5)))
GO
INSERT [dbo].[PartTransactionCosts] ([intPartTransactionID], [intPartTransactionCostID], [intCostType], [intQuantity], [intUnitMaterialCost], [intActualUnitMaterialCost]) VALUES (117726, 2, 2, CAST(1100.00000 AS Numeric(15, 5)), CAST(1.53503 AS Numeric(15, 5)), CAST(1.53503 AS Numeric(15, 5)))
GO
INSERT [dbo].[PartTransactionCosts] ([intPartTransactionID], [intPartTransactionCostID], [intCostType], [intQuantity], [intUnitMaterialCost], [intActualUnitMaterialCost]) VALUES (117726, 3, 3, CAST(1100.00000 AS Numeric(15, 5)), CAST(0.00000 AS Numeric(15, 5)), CAST(0.00000 AS Numeric(15, 5)))
GO
INSERT [dbo].[PartTransactionCosts] ([intPartTransactionID], [intPartTransactionCostID], [intCostType], [intQuantity], [intUnitMaterialCost], [intActualUnitMaterialCost]) VALUES (117726, 4, 4, CAST(1100.00000 AS Numeric(15, 5)), CAST(1.16410 AS Numeric(15, 5)), CAST(1.16410 AS Numeric(15, 5)))
GO
INSERT [dbo].[PartTransactionCosts] ([intPartTransactionID], [intPartTransactionCostID], [intCostType], [intQuantity], [intUnitMaterialCost], [intActualUnitMaterialCost]) VALUES (117725, 1, 1, CAST(555.00000 AS Numeric(15, 5)), CAST(1.61513 AS Numeric(15, 5)), CAST(1.61513 AS Numeric(15, 5)))
GO
INSERT [dbo].[PartTransactionCosts] ([intPartTransactionID], [intPartTransactionCostID], [intCostType], [intQuantity], [intUnitMaterialCost], [intActualUnitMaterialCost]) VALUES (117725, 2, 2, CAST(555.00000 AS Numeric(15, 5)), CAST(1.53503 AS Numeric(15, 5)), CAST(1.53503 AS Numeric(15, 5)))
GO
INSERT [dbo].[PartTransactionCosts] ([intPartTransactionID], [intPartTransactionCostID], [intCostType], [intQuantity], [intUnitMaterialCost], [intActualUnitMaterialCost]) VALUES (117725, 3, 3, CAST(555.00000 AS Numeric(15, 5)), CAST(0.00000 AS Numeric(15, 5)), CAST(0.00000 AS Numeric(15, 5)))
GO
INSERT [dbo].[PartTransactionCosts] ([intPartTransactionID], [intPartTransactionCostID], [intCostType], [intQuantity], [intUnitMaterialCost], [intActualUnitMaterialCost]) VALUES (117725, 4, 4, CAST(555.00000 AS Numeric(15, 5)), CAST(1.16410 AS Numeric(15, 5)), CAST(1.16410 AS Numeric(15, 5)))
GO
INSERT [dbo].[PartTransactionCosts] ([intPartTransactionID], [intPartTransactionCostID], [intCostType], [intQuantity], [intUnitMaterialCost], [intActualUnitMaterialCost]) VALUES (117727, 1, 1, CAST(10.00000 AS Numeric(15, 5)), CAST(1.61513 AS Numeric(15, 5)), CAST(1.61513 AS Numeric(15, 5)))
GO
INSERT [dbo].[PartTransactionCosts] ([intPartTransactionID], [intPartTransactionCostID], [intCostType], [intQuantity], [intUnitMaterialCost], [intActualUnitMaterialCost]) VALUES (117727, 2, 2, CAST(10.00000 AS Numeric(15, 5)), CAST(1.53503 AS Numeric(15, 5)), CAST(1.53503 AS Numeric(15, 5)))
GO
INSERT [dbo].[PartTransactionCosts] ([intPartTransactionID], [intPartTransactionCostID], [intCostType], [intQuantity], [intUnitMaterialCost], [intActualUnitMaterialCost]) VALUES (117727, 3, 3, CAST(10.00000 AS Numeric(15, 5)), CAST(0.00000 AS Numeric(15, 5)), CAST(0.00000 AS Numeric(15, 5)))
GO
INSERT [dbo].[PartTransactionCosts] ([intPartTransactionID], [intPartTransactionCostID], [intCostType], [intQuantity], [intUnitMaterialCost], [intActualUnitMaterialCost]) VALUES (117727, 4, 4, CAST(10.00000 AS Numeric(15, 5)), CAST(1.16410 AS Numeric(15, 5)), CAST(1.16410 AS Numeric(15, 5)))
GO
INSERT [dbo].[PartTransactionCosts] ([intPartTransactionID], [intPartTransactionCostID], [intCostType], [intQuantity], [intUnitMaterialCost], [intActualUnitMaterialCost]) VALUES (117513, 1, 1, CAST(555.00000 AS Numeric(15, 5)), CAST(1.61513 AS Numeric(15, 5)), CAST(1.61513 AS Numeric(15, 5)))
GO
INSERT [dbo].[PartTransactionCosts] ([intPartTransactionID], [intPartTransactionCostID], [intCostType], [intQuantity], [intUnitMaterialCost], [intActualUnitMaterialCost]) VALUES (117513, 2, 2, CAST(555.00000 AS Numeric(15, 5)), CAST(1.53503 AS Numeric(15, 5)), CAST(1.53503 AS Numeric(15, 5)))
GO
INSERT [dbo].[PartTransactionCosts] ([intPartTransactionID], [intPartTransactionCostID], [intCostType], [intQuantity], [intUnitMaterialCost], [intActualUnitMaterialCost]) VALUES (117513, 3, 3, CAST(555.00000 AS Numeric(15, 5)), CAST(0.00000 AS Numeric(15, 5)), CAST(0.00000 AS Numeric(15, 5)))
GO
INSERT [dbo].[PartTransactionCosts] ([intPartTransactionID], [intPartTransactionCostID], [intCostType], [intQuantity], [intUnitMaterialCost], [intActualUnitMaterialCost]) VALUES (117513, 4, 4, CAST(555.00000 AS Numeric(15, 5)), CAST(1.24865 AS Numeric(15, 5)), CAST(1.24865 AS Numeric(15, 5)))
GO
UPDATE: What this does.
First of all, this is from a DB backend for an ERP system called M1. Its table structures are immutable.
Receiving material to inventory or directly to a job is done through "part transactions." A part transaction joins to one of 4 possible part transaction cost types: 1) average cost 2) Last cost (regardless of the job in question) 3) Standard cost 4) Actual cost (as received directly to a job). Which is to be used is fixed by company-wide accounting policy settings.
Average cost is used for transactions that issue to a job from inventory, or return to inventory (unused) from a job. This is calculated in application code (VB) upon each transaction.
Material issues and returns NOT involving inventory are received directly to a job through various kinds of receipts, such as from a Purchase Order or Manufacturing Receipt (tables: ReceiptLines, MfgReceipt) - and a number of other possible methods (e.g. DMR, RMI, Inspection, Scrap, Shipment, Adjustment). These entities do not have the same footprint and are stored in different tables.
Unfortunately, the application code does not reliably store the "received" cost to a job via Receipt (PO) or Manufacturing receipt, so the data in PartTransactionCost (type 4, Actual) cannot be used as intended. Usually it does calculate correctly, but mysteriously sometimes it doesn't. It's a bug.
Therefore the only reliable way to return materials from a job at the same cost at which they were recieved by any kind of receipt, is to get the actual cost from the applicable receipt record. The COALESCE function selects the non-null join, in order of precedence, and where no receipt is found (i.e. all null results), the cost of last resort is the Average cost.
In the sample data given, There was one receipt of 555 quantity of item 21 at a unit cost of 1.25, then all 555 were returned (i.e. unused). This is done through a MaterialIssue transaction (whose sign is positive, though MaterialIssues have a negative Qty), resulting in a Net Quantity 0, Net Cost 0.00.
Then two more receipts were done for a total quantity of 1100, but at a different recieved unit cost than that of the first receipt. Then two more return transactions occured resulting in an net issue quantity again of 0. However, the code I inherited did not result in a net cost of zero, because the simple join produced a cross product of 3 x 3 receive and return transactions, for a spurious result of 9 components in the sum. So the net returned cost was wrong by multiples. This error was not noticed for a long time because that sequence of transactions is rare.
It must be noted that in this example the Last costs happen to be correct, but since they cannot be relied upon, I needed to get the actual received cost from the receipt record (table: MfgReceipts), and not from the receipt transaction. And the same technique is needed for other reciept types, such as in the table ReceiptLines. But only one receipt record can be used. In the solution provided, the last receipt's actual cost is returned only once, and used in the return transaction in lieu of the stored "last cost" - this results in a net issue quantity of zero and a net cost of zero.
The essence of the solution:
-- solved by example of answer 1-1) at
-- https://stackoverflow.com/questions/9275132/real-life-example-when-to-use-outer-cross-apply-in-sql
SELECT *
FROM
(SELECT
MI.imtJobID JobID
, MI.imtJobAssemblyID AssemblyID
, MI.imtJobMaterialID MaterialID
, MI.imtPartTransactionID
, intQuantity
FROM PartTransactions MI -- Material Issue
INNER JOIN PartTransactionCosts
ON imtPartTransactionID = intPartTransactionID
WHERE imtSource=3
AND intCostType = 4 -- Average cost, last resort
) MI
OUTER APPLY
(SELECT TOP 1
imtJobID JobID
, imtJobAssemblyID AssemblyID
, imtJobMaterialID MaterialID
, intActualUnitMaterialCost, imtPartTransactionID
, imtTableName, intCostType
FROM PartTransactions PTI JOIN PartTransactionCosts PTCI
on PTI.imtPartTransactionID=PTCI.intPartTransactionID
WHERE imtTableName='MfgReceipts'
AND intCostType = 4
AND PTI.imtJobID=MI.JobID AND PTI.imtJobAssemblyID=MI.AssemblyID AND PTI.imtJobMaterialID=MI.MaterialID
AND PTI.imtPartTransactionID < MI.imtPartTransactionID
-- most recent recieved cost prior to this issuance
ORDER BY PTI.imtPartTransactionID DESC
) MR
order by MI.MaterialID, MI.imtPartTransactionID
and whose result is more easily visualized thus:
Full implementation looks like this:
; WITH
MaterialIssues as (
SELECT
MI.imtJobID JobID
, MI.imtJobAssemblyID AssemblyID
, MI.imtJobMaterialID MaterialID
,
/* abstraction for different job types & sources*/
(
COALESCE(
MR.intActualUnitMaterialCost
, RL.intActualUnitMaterialCost
, intUnitMaterialCost
)
+ intUnitLaborCost
+ intUnitOverheadCost
+ intUnitSubcontractCost
+ intUnitDutyCost
+ intUnitFreightCost
+ intUnitMiscCost
) UnitCost
, intQuantity
Quantity
, imtSource
, imtJobType
, imtNonInventoryTransaction
, imtReceiptID
, imtTableName
FROM PartTransactions MI
INNER JOIN PartTransactionCosts
ON imtPartTransactionID = intPartTransactionID
LEFT JOIN Warehouses
ON imtPartWarehouseLocationID = imwWarehouseID
OUTER APPLY /* get single, most recent receieved cost */
(
SELECT TOP 1
imtJobID JobID, imtJobAssemblyID AssemblyID, imtJobMaterialID MaterialID
, imtPartTransactionID
, intActualUnitMaterialCost
FROM PartTransactionCosts PTCI
JOIN PartTransactions PTI
on imtPartTransactionID=intPartTransactionID
WHERE imtTableName='MfgReceipts'
AND intCostType = 4
AND PTI.imtJobID=MI.imtJobID
AND PTI.imtJobAssemblyID=MI.imtJobAssemblyID
AND PTI.imtJobMaterialID=MI.imtJobMaterialID
AND PTI.imtPartTransactionID < MI.imtPartTransactionID
ORDER BY PTI.imtPartTransactionID DESC
) MR
OUTER APPLY
(
SELECT TOP 1
imtJobID JobID, imtJobAssemblyID AssemblyID, imtJobMaterialID MaterialID
, imtPartTransactionID
, intActualUnitMaterialCost
FROM PartTransactionCosts PTCI
JOIN PartTransactions PTI
on imtPartTransactionID=intPartTransactionID
WHERE imtTableName='ReceiptLines'
AND intCostType = 4
AND PTI.imtJobID=MI.imtJobID
AND PTI.imtJobAssemblyID=MI.imtJobAssemblyID
AND PTI.imtJobMaterialID=MI.imtJobMaterialID
AND PTI.imtPartTransactionID < MI.imtPartTransactionID
ORDER BY PTI.imtPartTransactionID DESC
) RL
WHERE
imtTransactionDate < #dEndDate
AND imtTransactionDate >= #dStartDate
AND (
imtNonNettable = 0
OR (
imtNonNettable <> 0
AND ISNULL(imwDoNotIncludeInJobCosts, 0) = 0
)
)
AND intCostType = #nCostingMethod
/* always 1 */
)
, PartTransactionMaterialCosts as (
SELECT JobID, AssemblyID
, SUM(
UnitCost
*
(
(
CASE
WHEN imtSource = 3
/*MaterialIssueLines*/
THEN - 1
ELSE 1
END
) * Quantity
)
)
NetCost /*NOTE: negated conditionally on Source 3*/
FROM MaterialIssues
WHERE
imtNonInventoryTransaction <= #bShowNonInventory
AND imtSource IN(2, 3)
AND imtJobType IN(1, 3)
AND imtReceiptID = ''
AND Upper(imtTableName) NOT IN ('RECEIPTLINES', 'MFGRECEIPTS', 'MFGRECEIPTCOMPONENTS', 'RECEIPTCOMPONENTS')
GROUP BY JobID, AssemblyID
)
-- test:
Select * from PartTransactionMaterialCosts
Related
I've a bit complex requirement and for the understanding, let me make it clear with easy example. Suppose, we have to calculate the quantity of products purchased by consumers month-wise for the last 12 months. So what we do is the following:
SELECT DATENAME(MONTH, m.InvoiceDate) Month,
COUNT(m.Quantity) Quantity FROM CustomerInvoice m WHERE
DATEDIFF(month, m.InvoiceDate, GETDATE()) <= 12 AND YEAR(m.InvoiceDate) = '2018'
GROUP BY DATENAME(MONTH, m.InvoiceDate)
ORDER BY DATENAME(MONTH, m.InvoiceDate) DESC;
Output - So this is what we get:
Month Quantity
January 1
February 1
March 1
April 2
May 1
June 3
July 1
August 2
In my case, it's bit complicated as the following sample:
So if the input is July 2018, it should calculate the last 12 months quantity or value as well individual month's last 12 months value too. This seems to be something like recursive call. But pretty unsure how to accomplish this in the right way - Any ideas or samples would be highly appreciated - Thanks.
Sample Table With Data:
CREATE TABLE [dbo].[CustomerInvoice](
[ID] [int] IDENTITY(1,1) NOT NULL,
[ProductID] [int] NULL,
[Quantity] [float] NULL,
[Details] [varchar](max) NULL,
[InvoiceID] [varchar](40) NULL,
[CustomerID] [int] NULL,
[InvoiceDate] [datetime] NULL
)
INSERT [dbo].[CustomerInvoice] ([ID], [ProductID], [Quantity], [Details], [InvoiceID], [CustomerID], [InvoiceDate]) VALUES (1, 2, 2, N'Awesome Collections', N'20151129115910', 1, CAST(0x0000A94200000000 AS DateTime))
INSERT [dbo].[CustomerInvoice] ([ID], [ProductID], [Quantity], [Details], [InvoiceID], [CustomerID], [InvoiceDate]) VALUES (2, 1, 2, N'Joss Collections', N'20151129115910', 1, CAST(0x0000A94200000000 AS DateTime))
INSERT [dbo].[CustomerInvoice] ([ID], [ProductID], [Quantity], [Details], [InvoiceID], [CustomerID], [InvoiceDate]) VALUES (3, 2, 2, N'Awesome Collections', N'20151129115910', 1, CAST(0x0000A91900000000 AS DateTime))
INSERT [dbo].[CustomerInvoice] ([ID], [ProductID], [Quantity], [Details], [InvoiceID], [CustomerID], [InvoiceDate]) VALUES (4, 1, 2, N'Awesome Collections', N'20151129115910', 1, CAST(0x0000A8FC00000000 AS DateTime))
INSERT [dbo].[CustomerInvoice] ([ID], [ProductID], [Quantity], [Details], [InvoiceID], [CustomerID], [InvoiceDate]) VALUES (5, 2, 2, N'Awesome Collections', N'20151129115912', 2, CAST(0x0000A8F300000000 AS DateTime))
INSERT [dbo].[CustomerInvoice] ([ID], [ProductID], [Quantity], [Details], [InvoiceID], [CustomerID], [InvoiceDate]) VALUES (6, 1, 2, N'Joss Collections', N'20151129115912', 2, CAST(0x0000A8F400000000 AS DateTime))
INSERT [dbo].[CustomerInvoice] ([ID], [ProductID], [Quantity], [Details], [InvoiceID], [CustomerID], [InvoiceDate]) VALUES (7, 1, 4, N'Joss Collections', N'20151130120336', 1, CAST(0x0000A8DF00000000 AS DateTime))
INSERT [dbo].[CustomerInvoice] ([ID], [ProductID], [Quantity], [Details], [InvoiceID], [CustomerID], [InvoiceDate]) VALUES (8, 1, 10, N'Awesome Collections', N'20151130120336', 1, CAST(0x0000A8BA00000000 AS DateTime))
INSERT [dbo].[CustomerInvoice] ([ID], [ProductID], [Quantity], [Details], [InvoiceID], [CustomerID], [InvoiceDate]) VALUES (9, 2, 10, N'Awesome Collections', N'20151130120616', 1, CAST(0x0000A8BE00000000 AS DateTime))
INSERT [dbo].[CustomerInvoice] ([ID], [ProductID], [Quantity], [Details], [InvoiceID], [CustomerID], [InvoiceDate]) VALUES (10, 1, 10, N'Joss Collections', N'20151130120616', 1, CAST(0x0000A8AB00000000 AS DateTime))
INSERT [dbo].[CustomerInvoice] ([ID], [ProductID], [Quantity], [Details], [InvoiceID], [CustomerID], [InvoiceDate]) VALUES (11, 2, 12, N'Great', N'20151130125238', 2, CAST(0x0000A88700000000 AS DateTime))
INSERT [dbo].[CustomerInvoice] ([ID], [ProductID], [Quantity], [Details], [InvoiceID], [CustomerID], [InvoiceDate]) VALUES (12, 1, 12, N'Great', N'20151130125238', 2, CAST(0x0000A86F00000000 AS DateTime))
INSERT [dbo].[CustomerInvoice] ([ID], [ProductID], [Quantity], [Details], [InvoiceID], [CustomerID], [InvoiceDate]) VALUES (13, 2, 4, N'Great', N'20151202085309', 6, CAST(0x0000A85700000000 AS DateTime))
INSERT [dbo].[CustomerInvoice] ([ID], [ProductID], [Quantity], [Details], [InvoiceID], [CustomerID], [InvoiceDate]) VALUES (14, 1, 10, N'Joss Collections', N'20151202085309', 6, CAST(0x0000A81E00000000 AS DateTime))
INSERT [dbo].[CustomerInvoice] ([ID], [ProductID], [Quantity], [Details], [InvoiceID], [CustomerID], [InvoiceDate]) VALUES (15, 2, 10, N'Customer likes this a lot.', N'20151203101624', 1, CAST(0x0000A80F00000000 AS DateTime))
INSERT [dbo].[CustomerInvoice] ([ID], [ProductID], [Quantity], [Details], [InvoiceID], [CustomerID], [InvoiceDate]) VALUES (16, 2, 10, N'Customer likes this a lot.', N'20151203102205', 1, CAST(0x0000A7E500000000 AS DateTime))
INSERT [dbo].[CustomerInvoice] ([ID], [ProductID], [Quantity], [Details], [InvoiceID], [CustomerID], [InvoiceDate]) VALUES (17, 2, 2, N'Wao!! Great.', N'20151203103844', 1, CAST(0x0000A7CE00000000 AS DateTime))
INSERT [dbo].[CustomerInvoice] ([ID], [ProductID], [Quantity], [Details], [InvoiceID], [CustomerID], [InvoiceDate]) VALUES (18, 1, 4, N'Just Awesome.', N'20151203103844', 1, CAST(0x0000A7BD00000000 AS DateTime))
INSERT [dbo].[CustomerInvoice] ([ID], [ProductID], [Quantity], [Details], [InvoiceID], [CustomerID], [InvoiceDate]) VALUES (19, 2, 12, N'Customers just love the product.', N'20151203104143', 2, CAST(0x0000A78600000000 AS DateTime))
INSERT [dbo].[CustomerInvoice] ([ID], [ProductID], [Quantity], [Details], [InvoiceID], [CustomerID], [InvoiceDate]) VALUES (20, 1, 2, N'Awesome Collections.', N'20151203104143', 2, CAST(0x0000A79000000000 AS DateTime))
INSERT [dbo].[CustomerInvoice] ([ID], [ProductID], [Quantity], [Details], [InvoiceID], [CustomerID], [InvoiceDate]) VALUES (21, 2, 6, N'Awesome Collections.', N'20151203104945', 1, CAST(0x0000A78F00000000 AS DateTime))
INSERT [dbo].[CustomerInvoice] ([ID], [ProductID], [Quantity], [Details], [InvoiceID], [CustomerID], [InvoiceDate]) VALUES (22, 1, 6, N'Great Collection.', N'20151203104945', 1, CAST(0x0000A79300000000 AS DateTime))
INSERT [dbo].[CustomerInvoice] ([ID], [ProductID], [Quantity], [Details], [InvoiceID], [CustomerID], [InvoiceDate]) VALUES (23, 1, 10, N'Customer likes this a lot.', N'20151203105528', 1, CAST(0x0000A76F00000000 AS DateTime))
INSERT [dbo].[CustomerInvoice] ([ID], [ProductID], [Quantity], [Details], [InvoiceID], [CustomerID], [InvoiceDate]) VALUES (24, 2, 4, N'Great Collection.', N'20151203105528', 1, CAST(0x0000A75300000000 AS DateTime))
INSERT [dbo].[CustomerInvoice] ([ID], [ProductID], [Quantity], [Details], [InvoiceID], [CustomerID], [InvoiceDate]) VALUES (25, 2, 1, N'Just Great.', N'20151203110653', 7, CAST(0x0000A75C00000000 AS DateTime))
INSERT [dbo].[CustomerInvoice] ([ID], [ProductID], [Quantity], [Details], [InvoiceID], [CustomerID], [InvoiceDate]) VALUES (26, 1, 1, N'Customers are happy with the product.', N'20151203110653', 7, CAST(0x0000A76400000000 AS DateTime))
Update 1 - This calculation is done for last 12 months and please see how the quantity is calculated below:
Month-Year Quantity
Jul 2018 80 (Sum of quantity from Jul 2018 to Jun 2017)
Jun 2018 70 (Sum of quantity from Jun 2018 to May 2017)
May 2018 42 (Sum of quantity from May 2018 to Apr 2017)
Apr 2018 11 ...........................................
Mar 2018 6 ...........................................
Feb 2018 10 ...........................................
Jan 2018 16 ...........................................
Dec 2017 1 ...........................................
..........................................................
Jun 2017 10 (Sum of quantity from Jun 2017 to May 2016)
This answers the question for SQL Server 2012+ (the SQL Server version was not specified when I answered the question).
I would recommend using cumulative sums. This assumes that you have data for each month, but that seems reasonable. For a cumulative year-to-date:
SELECT YEAR(m.InvoiceDate) as yyyy,
MONTH(m.InvoiceDate) as mm,
SUM(m.Quantity) as Quantity,
SUM(SUM(m.Quantity)) OVER (PARTITION BY YEAR(m.InvoiceDate)
ORDER BY MONTH(m.InvoiceDate)
)
FROM CustomerInvoice m
WHERE YEAR(m.InvoiceDate) = 2018
GROUP BY YEAR(m.InvoiceDate), MONTH(m.InvoiceDate)
ORDER BY YEAR(m.InvoiceDate), MONTH(m.InvoiceDate);
Note that this uses SUM(m.Quantity) rather than COUNT(). SUM() makes more sense based on your description.
If you want a cumulative running 12-month sum, ignoring year boundaries, use a windowing clause:
SELECT YEAR(m.InvoiceDate) as yyyy,
MONTH(m.InvoiceDate) as mm,
SUM(m.Quantity) as Quantity,
SUM(SUM(m.Quantity)) OVER (PARTITION BY YEAR(m.InvoiceDate)
ORDER BY MONTH(m.InvoiceDate)
ROWS BETWEEN 11 PRECEDING AND CURRENT ROW
)
FROM CustomerInvoice m
GROUP BY YEAR(m.InvoiceDate), MONTH(m.InvoiceDate)
ORDER BY YEAR(m.InvoiceDate), MONTH(m.InvoiceDate);
EDIT:
In SQL Server 2008, you can express the first query as:
WITH ym as (
SELECT YEAR(m.InvoiceDate) as yyyy,
MONTH(m.InvoiceDate) as mm,
SUM(m.Quantity) as Quantity,
FROM CustomerInvoice m
WHERE YEAR(m.InvoiceDate) = 2018
GROUP BY YEAR(m.InvoiceDate), MONTH(m.InvoiceDate)
)
SELECT ym.yyyymm, ym.quantity, ym2.sum_Quantity)
FROM ym CROSS APPLY
(SELECT SUM(ym2.quantity) as sum_quantity
FROM ym ym2
WHERE ym.yyyy = ym2.yyyy AND ym2.month <= ym.month
) ym2
ORDER BY YEAR(m.InvoiceDate), MONTH(m.InvoiceDate);
For a rolling sum in SQL Server 2008:
WITH ym as (
SELECT YEAR(m.InvoiceDate) as yyyy,
MONTH(m.InvoiceDate) as mm,
SUM(m.Quantity) as Quantity,
FROM CustomerInvoice m
WHERE YEAR(m.InvoiceDate) = 2018
GROUP BY YEAR(m.InvoiceDate), MONTH(m.InvoiceDate)
)
SELECT ym.yyyymm, ym.quantity, ym2.sum_Quantity)
FROM ym CROSS APPLY
(SELECT SUM(ym2.quantity) as sum_quantity
FROM ym ym2
WHERE ym2.InvoiceDate >= DATEADD(year, -1, ym.InvoiceDate) AND
ym2.InvoiceDate <= ym.InvoiceDate
) ym2
ORDER BY YEAR(m.InvoiceDate), MONTH(m.InvoiceDate);
Try this:
WITH t (month_name,month_id,quantity)
AS
(
select month_name,month_id,quantity
from CustomerInvoice
cross apply (select datediff(month,0,InvoiceDate) month_id,format(InvoiceDate,'MMMM yyyy') month_name)stats
)
SELECT months_tbl.*,sum(quantity) from
(select distinct month_name,month_id from t)months_tbl
inner join t on t.month_id between months_tbl.month_id-11 and months_tbl.month_id
group by months_tbl.month_name,months_tbl.month_id
order by month_id asc
WITH Encashment AS (
SELECT T.MachineId, T.Amount, CAST(Occured AS DATETIME) AS Occured
FROM (VALUES
(1, 101, '2017-10-20 09:36:40.057')
,(1, 203, '2017-10-14 12:36:30.081')
,(1, 400, '2017-10-11 04:17:38.023')
) AS T(MachineId, Amount, Occured)
), MoneyAccepted AS (
SELECT T.MachineId, T.Amount, CAST(Occured AS DATETIME) AS Occured
FROM (VALUES
(1, 1, '2017-10-15 09:36:40.057')
,(1, 100, '2017-10-16 12:36:30.081')
,(1, 100, '2017-10-12 16:17:38.023')
,(1, 1, '2017-10-13 09:37:47.057')
,(1, 1, '2017-10-13 09:37:47.057')
,(1, 1, '2017-10-12 15:37:47.057')
,(1, 100, '2017-09-15 12:37:31.081')
,(1, 100, '2017-09-15 16:37:31.081')
,(1, 100, '2017-09-16 13:37:31.081')
,(1, 100, '2017-09-17 13:37:31.081')
) AS T(MachineId, Amount, Occured)
)
I can get Amount among two encashment.(Select Amount from Encashment).
But, I want to get amount from MoneyAccepted for every Encashment.
For example: Encashment happened in 20-10-2017,till this dateTime accepted 101(100(2017-10-16 12:36:30.081)+1(2017-10-15 09:36:40.057)) money.
How can I get that?
Thanks in advance!
I think what you are looking for is:
DECLARE #Encashment AS TABLE (MachineID INT, Amount INT, Occured DATETIME2)
DECLARE #MoneyAccepted AS TABLE (MachineID INT, Amount INT, Occured DATETIME2)
INSERT #Encashment (MachineID, Amount, Occured)
VALUES (1, 101, '20171020 09:36:40.057')
, (1, 203, '20171014 12:36:30.081')
, (1, 400, '20171011 04:17:38.023')
INSERT #MoneyAccepted (MachineID, Amount, Occured)
VALUES (1, 1, '20171015 09:36:40.057')
, (1, 100, '20171016 12:36:30.081')
, (1, 100, '20171012 16:17:38.023')
, (1, 100, '20171014 09:17:38.023')
, (1, 1, '20171013 09:37:47.057')
, (1, 1, '20171013 09:37:47.057')
, (1, 1, '20171012 15:37:31.081')
SELECT E.Occured AS Encashment_Occured
, SUM(MA.Amount) AS SUM_Amount
FROM #MoneyAccepted AS MA
INNER JOIN (
SELECT MachineID
, Amount
, Occured
, LAG(Occured) OVER(PARTITION BY MachineID ORDER BY Occured) AS Previous_Occured
FROM #Encashment
) AS E
ON E.MachineID = MA.MachineID
AND E.Occured > MA.Occured
AND E.Previous_Occured <= MA.Occured
GROUP BY E.Occured
Result:
+-----------------------------+------------+
| Encashment_Occured | SUM_Amount |
+-----------------------------+------------+
| 2017-10-14 12:36:30.0810000 | 203 |
| 2017-10-20 09:36:40.0570000 | 101 |
+-----------------------------+------------+
This uses LAG, which was introduced in sql server 2012, in order to get the range of applicable dates in a single row.
Please edit your question, remove html and use plain text for sample data.
I think you could use CROSS APPLY.
Try this:
WITH Encashment AS (
SELECT T.MachineId, T.Amount, CAST(Occured AS DATETIME) AS Occured
FROM (VALUES
(1, 101, '2017-10-20 09:36:40.057')
,(1, 203, '2017-10-14 12:36:30.081')
,(1, 400, '2017-10-11 04:17:38.023')
) AS T(MachineId, Amount, Occured)
), MoneyAccepted AS (
SELECT T.MachineId, T.Amount, CAST(Occured AS DATETIME) AS Occured
FROM (VALUES
(1, 1, '2017-10-15 09:36:40.057')
,(1, 100, '2017-10-16 12:36:30.081')
,(1, 100, '2017-10-12 16:17:38.023')
,(1, 1, '2017-10-13 09:37:47.057')
,(1, 1, '2017-10-13 09:37:47.057')
,(1, 1, '2017-10-12 15:37:47.057')
,(1, 100, '2017-09-15 12:37:31.081')
,(1, 100, '2017-09-15 16:37:31.081')
,(1, 100, '2017-09-16 13:37:31.081')
,(1, 100, '2017-09-17 13:37:31.081')
) AS T(MachineId, Amount, Occured)
)
SELECT M.*, EN.*
FROM MoneyAccepted AS M
CROSS APPLY (
SELECT TOP (1) E.* FROM Encashment AS E
WHERE E.MachineId = M.MachineId AND E.Occured > M.Occured
ORDER BY E.Occured ASC
) AS EN
Good evening everyone,
I'm working on a assignment and can't figure out the following, I have two tables:
CREATE TABLE Rental (
rental_id DECIMAL(12) PRIMARY KEY,
customer_id DECIMAL(12),
movie_id DECIMAL(12),
delivery_status VARCHAR(64),
return_status VARCHAR(64));
and
CREATE TABLE Movie (
movie_id DECIMAL(12) PRIMARY KEY,
DVD_id INTEGER NOT NULL,
title VARCHAR(64) NOT NULL,
stock_number DECIMAL(12),
director_id DECIMAL(12),
genre_id DECIMAL(12),
release_date DATE NOT NULL,
restrictions VARCHAR(256) NOT NULL);
I need to do the following, list the names of all movies that are currently unavailable, rented and not yet returned. And this is my query:
SELECT Movie.movie_id, Movie.title, Movie.stock_number
FROM Movie
WHERE (Movie.movie_id, Movie.stock_number) NOT IN (
SELECT Rental.movie_id,
COUNT(Rental.return_status) AS number_of_unreturned
FROM Rental
WHERE Rental.return_status = 'Unreturned'
GROUP BY Rental.movie_id
HAVING COUNT (Rental.return_status) > 1) AND Movie.stock_number = 0;
I definitely have movies in Movie table that are not "Unreturend" but I get no rows selected all the time. Any advices or directions to think would be appreciated. Thanks!
I edited this post and added the content of the tables.
INSERT INTO Movie VALUES (1, 1, 'Amblin', 1, 1, 1, CAST('18-Dec-1968' AS DATE), 'G');
INSERT INTO Movie VALUES (2, 2, 'Duel', 2, 1, 2, CAST('13-Nov-1971' AS DATE), 'R');
INSERT INTO Movie VALUES (3, 3, 'Something Evil ', 3, 1, 3, CAST('21-Jan-1972' AS DATE), 'R');
INSERT INTO Movie VALUES (4, 4, 'The Sugarland Express ', 4, 1, 4, CAST('05-Apr-1974' AS DATE), 'PG13');
INSERT INTO Movie VALUES (5, 5, 'Jaws', 5, 1, 3, CAST('20-Jun-1975' AS DATE), 'R');
INSERT INTO Movie VALUES (6, 6, 'Close Encounters of the Third Kind', 6, 1, 5, CAST('16-Nov-1977' AS DATE), 'PG13');
INSERT INTO Movie VALUES (7, 7, ' 1941', 7, 1, 6, CAST('14-Dec-1979' AS DATE), 'G');
INSERT INTO Movie VALUES (8, 8, 'Raiders of the Lost Ark', 8, 1, 7, CAST('12-Jun-1981' AS DATE), 'PG13');
INSERT INTO Movie VALUES (9, 9, 'E.T. the Extra-Terrestrial', 9, 1, 5, CAST('11-Jun-1982' AS DATE), 'PG13');
INSERT INTO Movie VALUES (10, 10, 'Twilight Zone: The Movie', 10, 1, 3, CAST('24-Jun-1983' AS DATE), 'R');
INSERT INTO Movie VALUES (11, 11, 'Indiana Jones and the Temple of Doom', 11, 1, 7, CAST('23-May-1984' AS DATE), 'PG13');
INSERT INTO Movie VALUES (12, 12, 'The Color Purple', 12, 1, 4, CAST('18-Dec-1985' AS DATE), 'G');
INSERT INTO Movie VALUES (13, 13, 'Empire of the Sun', 13, 1, 4, CAST('25-Dec-1987' AS DATE), 'G');
INSERT INTO Movie VALUES (14, 14, 'Always', 14, 1, 4, CAST('22-Dec-1989' AS DATE), 'G');
INSERT INTO Movie VALUES (15, 15, 'Indiana Jones and the Last Crusade', 15, 1, 7, CAST('24-May-1989' AS DATE), 'G');
INSERT INTO Movie VALUES (16, 16, 'Hook', 16, 1, 8, CAST('11-Dec-1991' AS DATE), 'G');
INSERT INTO Movie VALUES (17, 17, 'Jurassic Park ', 17, 1, 5, CAST('11-Jun-1993' AS DATE), 'PG13');
INSERT INTO Movie VALUES (18, 18, 'Schindler''s List', 18, 1, 4, CAST('15-Dec-1993' AS DATE), 'PG13');
INSERT INTO Movie VALUES (19, 19, 'The Lost World: Jurassic Park', 19, 1, 5, CAST('23-May-1997' AS DATE), 'PG13');
INSERT INTO Movie VALUES (20, 20, 'Amistad', 20, 1, 4, CAST('10-Dec-1997' AS DATE), 'PG13');
INSERT INTO Movie VALUES (21, 21, 'Saving Private Ryan', 21, 1, 4, CAST('24-Jul-1998' AS DATE), 'PG13');
INSERT INTO Movie VALUES (22, 22, 'A.I. Artificial Intelligence', 22, 1, 4, CAST('29-Jun-2001' AS DATE), 'PG13');
INSERT INTO Movie VALUES (23, 23, 'Minority Report', 23, 1, 7, CAST('21-Jun-2002' AS DATE), 'PG13');
INSERT INTO Movie VALUES (24, 24, 'Catch Me If You Can', 24, 1, 8, CAST('25-Dec-2002' AS DATE), 'PG13');
INSERT INTO Movie VALUES (25, 25, ' The Terminal', 25, 1, 4, CAST('18-Jun-2004' AS DATE), 'G');
INSERT INTO Movie VALUES (26, 26, 'War of the Worlds', 26, 1, 5, CAST('29-Jun-2005' AS DATE), 'PG13');
INSERT INTO Movie VALUES (27, 27, 'Munich', 27, 1, 4, CAST('23-Dec-2005' AS DATE), 'PG13');
INSERT INTO Movie VALUES (28, 28, 'Indiana Jones and the Kingdom of the Crystal Skull', 28, 1, 7, CAST('22-May-2008' AS DATE), 'PG13');
INSERT INTO Movie VALUES (29, 29, 'The Adventures of Tintin', 28, 1, 7, CAST('21-Dec-2011' AS DATE), 'PG13');
INSERT INTO Movie VALUES (30, 30, 'War Horse', 30, 1, 4, CAST('25-Dec-2011' AS DATE), 'PG13');
INSERT INTO Movie VALUES (31, 31, 'Lincoln', 31, 1, 4, CAST('09-Nov-2012' AS DATE), 'PG13');
INSERT INTO Movie VALUES (32, 32, 'Bridge of Spies', 32, 1, 4, CAST('16-Oct-2015' AS DATE), 'PG13');
INSERT INTO Movie VALUES (33, 33, 'The BFG', 33, 1, 8, CAST('01-Jul-2016' AS DATE), 'PG13');
INSERT INTO Movie VALUES (34, 34, 'Praying with Anger', 34, 2, 5, CAST('12-Sep-1992' AS DATE), 'PG13');
INSERT INTO Movie VALUES (35, 35, 'Wide Awake', 35, 2, 4, CAST('20-Mar-1998' AS DATE), 'G');
INSERT INTO Movie VALUES (36, 36, 'The Sixth Sense', 36, 2, 2, CAST('06-Aug-1999' AS DATE), 'PG13');
INSERT INTO Movie VALUES (37, 37, 'Unbreakable', 37, 2, 2, CAST('22-Nov-2000' AS DATE), 'PG13');
INSERT INTO Movie VALUES (38, 38, 'Signs', 38, 2, 2, CAST('02-Aug-2002' AS DATE), 'PG13');
INSERT INTO Movie VALUES (39, 39, 'The Village', 39, 2, 2, CAST('30-Jul-2004' AS DATE), 'PG13');
INSERT INTO Movie VALUES (40, 40, 'Lady in the Water', 40, 2, 8, CAST('21-Jul-2006' AS DATE), 'PG13');
INSERT INTO Movie VALUES (41, 41, 'The Happening', 41, 2, 2, CAST('13-Jun-2008' AS DATE), 'R');
INSERT INTO Movie VALUES (42, 42, 'The Last Airbender', 42, 2, 7, CAST('02-Jul-2010' AS DATE), 'G');
INSERT INTO Movie VALUES (43, 43, 'After Earth', 43, 2, 7, CAST('31-May-2013' AS DATE), 'G');
INSERT INTO Movie VALUES (44, 44, 'The Visit', 44, 2, 3, CAST('11-Sep-2015' AS DATE), 'R');
INSERT INTO Movie VALUES (45, 45, 'Split', 45, 2, 2, CAST('20-Jan-2017' AS DATE), 'PG13');
and
INSERT INTO Rental VALUES (sequence_rental.NEXTVAL, 1, 1, 'Delivered', 'Unreturned');
INSERT INTO Rental VALUES (sequence_rental.NEXTVAL, 2, 1, 'Delivered', 'Unreturned');
INSERT INTO Rental VALUES (sequence_rental.NEXTVAL, 3, 6, 'Delivered', 'Unreturned');
INSERT INTO Rental VALUES (sequence_rental.NEXTVAL, 4, 7, 'Delivered', 'Unreturned');
INSERT INTO Rental VALUES (sequence_rental.NEXTVAL, 2, 2, 'Delivered', 'Unreturned');
INSERT INTO Rental VALUES (sequence_rental.NEXTVAL, 2, 37, 'Delivered', 'Unreturned');
INSERT INTO Rental VALUES (sequence_rental.NEXTVAL, 5, 1, 'Delivered', 'Unreturned');
INSERT INTO Rental VALUES (sequence_rental.NEXTVAL, 5, 24, 'Delivered', 'Unreturned');
INSERT INTO Rental VALUES (sequence_rental.NEXTVAL, 5, 3, 'Delivered', 'Unreturned');
INSERT INTO Rental VALUES (sequence_rental.NEXTVAL, 6, 13, 'Delivered', 'Unreturned');
INSERT INTO Rental VALUES (sequence_rental.NEXTVAL, 6, 2, 'Delivered', 'Unreturned');
INSERT INTO Rental VALUES (sequence_rental.NEXTVAL, 6, 8, 'Delivered', 'Unreturned');
INSERT INTO Rental VALUES (sequence_rental.NEXTVAL, 6, 1, 'Delivered', 'Unreturned');
INSERT INTO Rental VALUES (sequence_rental.NEXTVAL, 5, 2, 'Delivered', 'Unreturned');
INSERT INTO Rental VALUES (sequence_rental.NEXTVAL, 5, 3, 'Delivered', 'Unreturned');
INSERT INTO Rental VALUES (sequence_rental.NEXTVAL, 3, 27, 'Delivered', 'Returned');
Sorry if that is a too long post.
I don't want to write the code since you are a student. I'll give some direction though. In your where clause you're comparing (movie.movie_id = rental.movie_id) and (movie.stock_number = count(rental.return_status). Comparing the stock_number to the count of returns is incorrect.
When returning columns from multiple tables, use a join. The in statement does a comparison. Count is not being returned.
Join movies and the "in" subquery on movie_id. Create an alias on the subquery so you can join it.
Add the count column to the topmost outer select
Please try, if this logic is correct, I did not quite understand column naming. You might change last row (having) to correct it.
SELECT
m.movie_id, m.title, m.stock_number -- Getting movie id, movie title, stock number
FROM Movie m -- from movie table
JOIN rental r
ON (m.movie_id = r.movie_id) -- joining rental table in movie_id
WHERE
r.return_status = 'Unreturned' -- where return_status is unreturned
GROUP BY
m.movie_id, m.title, m.stock_number -- grouping_by (same as select)
HAVING
SUM(r.movie_id) > m.stock_number; -- restricting group by quantity
To resolve the query try first to break it down in the components you need.
In this case you need to compare the number of rented movies against the stock of movies.
So write 2 separte queries:
1 - One that will provide the movie id and the number to movies in stock.
2 - Another for the movie id and the number of rentals. For this one you have to count the unretured.
After you have the two queries, you can use them as subqueries of a higer level query that treats each or these queries as a table joined by the common id field.
And add awhere clause comparing the stock with the counted field.
Example:
Table A: id, name, age
Table B: table_b_id, table_a_id, telephone, address
Query 1: select id, name, age from A
Query 2: select table_a_id, telephone, address from B
select Q1.id, Q1.name, Q1.age, Q2telephone, Q2.address
from
(select A.id, A.name, A.age from A) Q1,
(select B.table_a_id, B.telephone, B.address from B) Q2
where
Q1.id = Q2.table_a_id
I am trying to find the best way to do this within SQL (or whether SQL is the recommended route to take at all)
I have a couple tables, with a structure as explained below (de-normalized for explaining ease). One is a table of employees with their "tag" definitions. The second is a table of employee groups, along with the criteria for the group.
Employee Table
EmployeeId | Tags
-----------------------------
1 | Country|US
1 | EmployeeType|FullTime
2 | Country|CA
2 | EmployeeType|FullTime
3 | Country|BR
3 | EmployeeType|FullTime
4 | Country|US
4 | EmployeeType|FullTime
4 | Language|Spanish
Group Table
GroupId | Tags | OperatorGroup
---------------------------------------------------------------------------------------------
1 | Country|US | D68BF531-FD9B-4A0E-886E-7420BDFFE380
1 | Country|CA | D68BF531-FD9B-4A0E-886E-7420BDFFE380
1 | EmployeeType|FullTime | 0B97D792-7659-42EF-8036-D19B1A0D5197
2 | Country|BR | CE61BC17-2567-4B02-AE5E-F5EA40265EE7
2 | EmployeeType|FullTime | 6A3418F6-C4FD-40E2-97B3-0F9E87759939
3 | Country|US | BF3DAC05-8131-463F-976E-28099628842D
3 | EmployeeType|FullTime | D63CEDC2-D15F-4E05-B3B9-0109121B3C75
3 | Language|Spanish | 3AA247D1-3779-48BD-8A2C-B9C8A084E32D
In the above table "Group", OperatorGroup determines the condition / operator for that group. Within the same GroupId, I use the OR operator within the same OperatorGroup, and the AND operator otherwise. For GroupId == 1, both Country|US and Country|CA has the same OperatorGroup, hence would be joined by an OR clause, in words, "You will match GroupId = 1 if your country is (US OR CA) AND you are a full time employee"
The result that I am looking for is the groups that the employee is part of. Based on the above data, I would expect the below
EmployeeGroups Result
EmployeeId | GroupId
------------------------------
1 | 1
2 | 1
3 | 2
4 | 1
4 | 3
Is a SQL-only solution (TSQL - SQL Server 2012) too ambitious? Any pointers either way would be much appreciated.
I should add that the tag names (Country, EmployeeType and Language) are just examples, I can have the tag names and values (US, CA etc...) added run time.
I solved this. I had to change the schema and the rules of the group table a lil bit
Group Table
GroupId | Tags | OperatorGroup
---------------------------------------------------------------------------------------------
1 | Country|US | D68BF531-FD9B-4A0E-886E-7420BDFFE380
1 | EmployeeType|FullTime | D68BF531-FD9B-4A0E-886E-7420BDFFE380
1 | Country|CA | 0B97D792-7659-42EF-8036-D19B1A0D5197
1 | EmployeeType|FullTime | 0B97D792-7659-42EF-8036-D19B1A0D5197
2 | Country|BR | CE61BC17-2567-4B02-AE5E-F5EA40265EE7
2 | EmployeeType|FullTime | CE61BC17-2567-4B02-AE5E-F5EA40265EE7
3 | Country|US | BF3DAC05-8131-463F-976E-28099628842D
3 | EmployeeType|FullTime | BF3DAC05-8131-463F-976E-28099628842D
3 | Language|Spanish | BF3DAC05-8131-463F-976E-28099628842D
Each unique OperatorGroup within a value of GroupId represents a complete set of rules that match a specific group. That way I can pivot my employee and group tables and do a join to find matching groups.
I have pasted my schema data + queries below.
Schema
CREATE TABLE [dbo].[Employee]([EmployeeId] [int], [EmployerId] [int] NOT NULL, [Name] [nvarchar](50) NOT NULL)
CREATE TABLE [dbo].[EmployeeTag]([EmployeeTagId] [int], [EmployeeId] [int] NOT NULL, [TagId] [int] NOT NULL)
CREATE TABLE [dbo].[Employer]([EmployerId] [int], [Name] [nvarchar](50) NOT NULL)
CREATE TABLE [dbo].[Group]([GroupId] [int], [EmployerId] [int] NOT NULL, [Name] [nvarchar](50) NOT NULL)
CREATE TABLE [dbo].[GroupDefinition]([GroupDefinitionId] [int], [GroupId] [int] NOT NULL, [TagId] [int] NOT NULL, [Grouping] [uniqueidentifier] NOT NULL)
CREATE TABLE [dbo].[Tag]([TagId] [int], [Name] [nvarchar](50) NOT NULL, [Value] [nvarchar](50) NOT NULL)
Data
INSERT [dbo].[Employer] ([EmployerId], [Name]) VALUES (1, N'Fabrikam')
INSERT [dbo].[Employee] ([EmployeeId], [EmployerId], [Name]) VALUES (1, 1, N'John Smith')
INSERT [dbo].[Employee] ([EmployeeId], [EmployerId], [Name]) VALUES (2, 1, N'Jane Miller')
INSERT [dbo].[Employee] ([EmployeeId], [EmployerId], [Name]) VALUES (3, 1, N'Nelda Maughan')
INSERT [dbo].[Employee] ([EmployeeId], [EmployerId], [Name]) VALUES (4, 1, N'Joe Anderson')
INSERT [dbo].[Employee] ([EmployeeId], [EmployerId], [Name]) VALUES (5, 1, N'Ami Mcmanis')
INSERT [dbo].[Employee] ([EmployeeId], [EmployerId], [Name]) VALUES (6, 1, N'Charlena Ashbaugh')
INSERT [dbo].[Employee] ([EmployeeId], [EmployerId], [Name]) VALUES (7, 1, N'Matt Tutino')
INSERT [dbo].[Employee] ([EmployeeId], [EmployerId], [Name]) VALUES (8, 1, N'Sulema Alexandria')
INSERT [dbo].[Employee] ([EmployeeId], [EmployerId], [Name]) VALUES (9, 1, N'Ema Wolak')
INSERT [dbo].[Employee] ([EmployeeId], [EmployerId], [Name]) VALUES (10, 1, N'Marinda Krejci')
INSERT [dbo].[Employee] ([EmployeeId], [EmployerId], [Name]) VALUES (11, 1, N'Felipa Chew')
INSERT [dbo].[Employee] ([EmployeeId], [EmployerId], [Name]) VALUES (12, 1, N'Armand Hosier')
INSERT [dbo].[Employee] ([EmployeeId], [EmployerId], [Name]) VALUES (13, 1, N'Roland Blunk')
INSERT [dbo].[Employee] ([EmployeeId], [EmployerId], [Name]) VALUES (14, 1, N'Ellen Frasier')
INSERT [dbo].[Employee] ([EmployeeId], [EmployerId], [Name]) VALUES (15, 1, N'Nicolle Tarbell')
INSERT [dbo].[Employee] ([EmployeeId], [EmployerId], [Name]) VALUES (16, 1, N'Christopher Lautenschlage')
INSERT [dbo].[Employee] ([EmployeeId], [EmployerId], [Name]) VALUES (17, 1, N'Nelson Maughan')
INSERT [dbo].[Employee] ([EmployeeId], [EmployerId], [Name]) VALUES (18, 1, N'Wes Boyd')
INSERT [dbo].[Employee] ([EmployeeId], [EmployerId], [Name]) VALUES (19, 1, N'Jason Lessley')
INSERT [dbo].[Employee] ([EmployeeId], [EmployerId], [Name]) VALUES (20, 1, N'Jesus Purves')
INSERT [dbo].[Tag] ([TagId], [Name], [Value]) VALUES (1, N'Country', N'United States')
INSERT [dbo].[Tag] ([TagId], [Name], [Value]) VALUES (2, N'Country', N'Canada')
INSERT [dbo].[Tag] ([TagId], [Name], [Value]) VALUES (3, N'Country', N'Brazil')
INSERT [dbo].[Tag] ([TagId], [Name], [Value]) VALUES (4, N'EmployeeType', N'Full Time')
INSERT [dbo].[Tag] ([TagId], [Name], [Value]) VALUES (5, N'EmployeeType', N'Part Time')
INSERT [dbo].[Tag] ([TagId], [Name], [Value]) VALUES (6, N'Language', N'Spanish')
INSERT [dbo].[Tag] ([TagId], [Name], [Value]) VALUES (7, N'Language', N'French')
INSERT [dbo].[Tag] ([TagId], [Name], [Value]) VALUES (8, N'Language', N'English')
INSERT [dbo].[EmployeeTag] ([EmployeeTagId], [EmployeeId], [TagId]) VALUES (1, 1, 1)
INSERT [dbo].[EmployeeTag] ([EmployeeTagId], [EmployeeId], [TagId]) VALUES (2, 1, 4)
INSERT [dbo].[EmployeeTag] ([EmployeeTagId], [EmployeeId], [TagId]) VALUES (3, 1, 6)
INSERT [dbo].[EmployeeTag] ([EmployeeTagId], [EmployeeId], [TagId]) VALUES (4, 2, 2)
INSERT [dbo].[EmployeeTag] ([EmployeeTagId], [EmployeeId], [TagId]) VALUES (5, 2, 5)
INSERT [dbo].[EmployeeTag] ([EmployeeTagId], [EmployeeId], [TagId]) VALUES (6, 2, 6)
INSERT [dbo].[EmployeeTag] ([EmployeeTagId], [EmployeeId], [TagId]) VALUES (7, 3, 2)
INSERT [dbo].[EmployeeTag] ([EmployeeTagId], [EmployeeId], [TagId]) VALUES (8, 3, 4)
INSERT [dbo].[EmployeeTag] ([EmployeeTagId], [EmployeeId], [TagId]) VALUES (9, 3, 7)
INSERT [dbo].[EmployeeTag] ([EmployeeTagId], [EmployeeId], [TagId]) VALUES (10, 4, 3)
INSERT [dbo].[EmployeeTag] ([EmployeeTagId], [EmployeeId], [TagId]) VALUES (11, 4, 4)
INSERT [dbo].[EmployeeTag] ([EmployeeTagId], [EmployeeId], [TagId]) VALUES (12, 4, 7)
INSERT [dbo].[EmployeeTag] ([EmployeeTagId], [EmployeeId], [TagId]) VALUES (13, 5, 2)
INSERT [dbo].[EmployeeTag] ([EmployeeTagId], [EmployeeId], [TagId]) VALUES (14, 5, 4)
INSERT [dbo].[EmployeeTag] ([EmployeeTagId], [EmployeeId], [TagId]) VALUES (15, 5, 6)
INSERT [dbo].[EmployeeTag] ([EmployeeTagId], [EmployeeId], [TagId]) VALUES (16, 6, 1)
INSERT [dbo].[EmployeeTag] ([EmployeeTagId], [EmployeeId], [TagId]) VALUES (17, 6, 6)
INSERT [dbo].[EmployeeTag] ([EmployeeTagId], [EmployeeId], [TagId]) VALUES (18, 7, 1)
INSERT [dbo].[EmployeeTag] ([EmployeeTagId], [EmployeeId], [TagId]) VALUES (19, 7, 5)
INSERT [dbo].[EmployeeTag] ([EmployeeTagId], [EmployeeId], [TagId]) VALUES (20, 7, 7)
INSERT [dbo].[EmployeeTag] ([EmployeeTagId], [EmployeeId], [TagId]) VALUES (21, 8, 3)
INSERT [dbo].[EmployeeTag] ([EmployeeTagId], [EmployeeId], [TagId]) VALUES (22, 8, 4)
INSERT [dbo].[EmployeeTag] ([EmployeeTagId], [EmployeeId], [TagId]) VALUES (23, 9, 1)
INSERT [dbo].[EmployeeTag] ([EmployeeTagId], [EmployeeId], [TagId]) VALUES (24, 9, 4)
INSERT [dbo].[EmployeeTag] ([EmployeeTagId], [EmployeeId], [TagId]) VALUES (25, 9, 7)
INSERT [dbo].[EmployeeTag] ([EmployeeTagId], [EmployeeId], [TagId]) VALUES (26, 10, 3)
INSERT [dbo].[EmployeeTag] ([EmployeeTagId], [EmployeeId], [TagId]) VALUES (27, 10, 6)
INSERT [dbo].[EmployeeTag] ([EmployeeTagId], [EmployeeId], [TagId]) VALUES (28, 11, 1)
INSERT [dbo].[EmployeeTag] ([EmployeeTagId], [EmployeeId], [TagId]) VALUES (29, 11, 4)
INSERT [dbo].[EmployeeTag] ([EmployeeTagId], [EmployeeId], [TagId]) VALUES (30, 11, 8)
INSERT [dbo].[EmployeeTag] ([EmployeeTagId], [EmployeeId], [TagId]) VALUES (31, 12, 1)
INSERT [dbo].[EmployeeTag] ([EmployeeTagId], [EmployeeId], [TagId]) VALUES (32, 12, 5)
INSERT [dbo].[EmployeeTag] ([EmployeeTagId], [EmployeeId], [TagId]) VALUES (33, 12, 6)
INSERT [dbo].[EmployeeTag] ([EmployeeTagId], [EmployeeId], [TagId]) VALUES (34, 13, 1)
INSERT [dbo].[EmployeeTag] ([EmployeeTagId], [EmployeeId], [TagId]) VALUES (35, 13, 5)
INSERT [dbo].[EmployeeTag] ([EmployeeTagId], [EmployeeId], [TagId]) VALUES (36, 13, 8)
INSERT [dbo].[EmployeeTag] ([EmployeeTagId], [EmployeeId], [TagId]) VALUES (37, 14, 2)
INSERT [dbo].[EmployeeTag] ([EmployeeTagId], [EmployeeId], [TagId]) VALUES (38, 14, 4)
INSERT [dbo].[EmployeeTag] ([EmployeeTagId], [EmployeeId], [TagId]) VALUES (39, 14, 8)
INSERT [dbo].[EmployeeTag] ([EmployeeTagId], [EmployeeId], [TagId]) VALUES (40, 15, 2)
INSERT [dbo].[EmployeeTag] ([EmployeeTagId], [EmployeeId], [TagId]) VALUES (41, 15, 5)
INSERT [dbo].[EmployeeTag] ([EmployeeTagId], [EmployeeId], [TagId]) VALUES (42, 15, 8)
INSERT [dbo].[EmployeeTag] ([EmployeeTagId], [EmployeeId], [TagId]) VALUES (43, 16, 3)
INSERT [dbo].[EmployeeTag] ([EmployeeTagId], [EmployeeId], [TagId]) VALUES (44, 16, 8)
INSERT [dbo].[EmployeeTag] ([EmployeeTagId], [EmployeeId], [TagId]) VALUES (45, 17, 1)
INSERT [dbo].[EmployeeTag] ([EmployeeTagId], [EmployeeId], [TagId]) VALUES (46, 17, 8)
INSERT [dbo].[EmployeeTag] ([EmployeeTagId], [EmployeeId], [TagId]) VALUES (47, 18, 8)
INSERT [dbo].[EmployeeTag] ([EmployeeTagId], [EmployeeId], [TagId]) VALUES (48, 19, 2)
INSERT [dbo].[EmployeeTag] ([EmployeeTagId], [EmployeeId], [TagId]) VALUES (49, 19, 7)
INSERT [dbo].[EmployeeTag] ([EmployeeTagId], [EmployeeId], [TagId]) VALUES (50, 20, 3)
INSERT [dbo].[EmployeeTag] ([EmployeeTagId], [EmployeeId], [TagId]) VALUES (51, 20, 4)
INSERT [dbo].[EmployeeTag] ([EmployeeTagId], [EmployeeId], [TagId]) VALUES (52, 20, 6)
INSERT [dbo].[Group] ([GroupId], [EmployerId], [Name]) VALUES (1, 1, N'US Full Timers')
INSERT [dbo].[Group] ([GroupId], [EmployerId], [Name]) VALUES (2, 1, N'CA Full Timers')
INSERT [dbo].[Group] ([GroupId], [EmployerId], [Name]) VALUES (3, 1, N'NA Spanish Full Timers')
INSERT [dbo].[Group] ([GroupId], [EmployerId], [Name]) VALUES (4, 1, N'NA French Full Timers')
INSERT [dbo].[Group] ([GroupId], [EmployerId], [Name]) VALUES (5, 1, N'US Part Timers')
INSERT [dbo].[Group] ([GroupId], [EmployerId], [Name]) VALUES (6, 1, N'CA Part Timers')
INSERT [dbo].[Group] ([GroupId], [EmployerId], [Name]) VALUES (7, 1, N'NA Spanish Part Timers')
INSERT [dbo].[Group] ([GroupId], [EmployerId], [Name]) VALUES (8, 1, N'NA French Part Timers')
INSERT [dbo].[Group] ([GroupId], [EmployerId], [Name]) VALUES (9, 1, N'BR Spanish Full Timers')
INSERT [dbo].[Group] ([GroupId], [EmployerId], [Name]) VALUES (10, 1, N'Spanish Speakers')
INSERT [dbo].[Group] ([GroupId], [EmployerId], [Name]) VALUES (11, 1, N'US Employees')
INSERT [dbo].[Group] ([GroupId], [EmployerId], [Name]) VALUES (12, 1, N'BR Employees')
INSERT [dbo].[GroupDefinition] ([GroupDefinitionId], [GroupId], [TagId], [Grouping]) VALUES (1, 1, 1, N'8e336244-94ac-4e62-a719-0a4a0b01a6f2')
INSERT [dbo].[GroupDefinition] ([GroupDefinitionId], [GroupId], [TagId], [Grouping]) VALUES (2, 1, 4, N'8e336244-94ac-4e62-a719-0a4a0b01a6f2')
INSERT [dbo].[GroupDefinition] ([GroupDefinitionId], [GroupId], [TagId], [Grouping]) VALUES (3, 2, 2, N'b3c87fe8-7b9f-4648-9708-20a460cf9314')
INSERT [dbo].[GroupDefinition] ([GroupDefinitionId], [GroupId], [TagId], [Grouping]) VALUES (4, 2, 4, N'b3c87fe8-7b9f-4648-9708-20a460cf9314')
INSERT [dbo].[GroupDefinition] ([GroupDefinitionId], [GroupId], [TagId], [Grouping]) VALUES (5, 3, 1, N'36fa7924-fa11-4772-b632-84c79b6bbb1b')
INSERT [dbo].[GroupDefinition] ([GroupDefinitionId], [GroupId], [TagId], [Grouping]) VALUES (6, 3, 4, N'36fa7924-fa11-4772-b632-84c79b6bbb1b')
INSERT [dbo].[GroupDefinition] ([GroupDefinitionId], [GroupId], [TagId], [Grouping]) VALUES (7, 3, 6, N'36fa7924-fa11-4772-b632-84c79b6bbb1b')
INSERT [dbo].[GroupDefinition] ([GroupDefinitionId], [GroupId], [TagId], [Grouping]) VALUES (8, 3, 2, N'dfa7f0f9-aa7a-401b-8bfd-804aeadff1a9')
INSERT [dbo].[GroupDefinition] ([GroupDefinitionId], [GroupId], [TagId], [Grouping]) VALUES (9, 3, 4, N'dfa7f0f9-aa7a-401b-8bfd-804aeadff1a9')
INSERT [dbo].[GroupDefinition] ([GroupDefinitionId], [GroupId], [TagId], [Grouping]) VALUES (10, 3, 6, N'dfa7f0f9-aa7a-401b-8bfd-804aeadff1a9')
INSERT [dbo].[GroupDefinition] ([GroupDefinitionId], [GroupId], [TagId], [Grouping]) VALUES (11, 4, 1, N'b857e999-0a7e-49fe-b138-88aed2d81aa3')
INSERT [dbo].[GroupDefinition] ([GroupDefinitionId], [GroupId], [TagId], [Grouping]) VALUES (12, 4, 4, N'b857e999-0a7e-49fe-b138-88aed2d81aa3')
INSERT [dbo].[GroupDefinition] ([GroupDefinitionId], [GroupId], [TagId], [Grouping]) VALUES (13, 4, 7, N'b857e999-0a7e-49fe-b138-88aed2d81aa3')
INSERT [dbo].[GroupDefinition] ([GroupDefinitionId], [GroupId], [TagId], [Grouping]) VALUES (14, 4, 2, N'296741c2-de6f-46ca-adcc-5b552fb4b0eb')
INSERT [dbo].[GroupDefinition] ([GroupDefinitionId], [GroupId], [TagId], [Grouping]) VALUES (15, 4, 4, N'296741c2-de6f-46ca-adcc-5b552fb4b0eb')
INSERT [dbo].[GroupDefinition] ([GroupDefinitionId], [GroupId], [TagId], [Grouping]) VALUES (16, 4, 7, N'296741c2-de6f-46ca-adcc-5b552fb4b0eb')
INSERT [dbo].[GroupDefinition] ([GroupDefinitionId], [GroupId], [TagId], [Grouping]) VALUES (17, 5, 1, N'48fd52d4-141a-43d3-8dea-69b9df6337ed')
INSERT [dbo].[GroupDefinition] ([GroupDefinitionId], [GroupId], [TagId], [Grouping]) VALUES (18, 5, 5, N'48fd52d4-141a-43d3-8dea-69b9df6337ed')
INSERT [dbo].[GroupDefinition] ([GroupDefinitionId], [GroupId], [TagId], [Grouping]) VALUES (19, 6, 2, N'e85ba82a-0ca7-410b-ba35-726bd86a8621')
INSERT [dbo].[GroupDefinition] ([GroupDefinitionId], [GroupId], [TagId], [Grouping]) VALUES (20, 6, 5, N'e85ba82a-0ca7-410b-ba35-726bd86a8621')
INSERT [dbo].[GroupDefinition] ([GroupDefinitionId], [GroupId], [TagId], [Grouping]) VALUES (21, 7, 1, N'bb656fc1-8ccd-4ff6-85ec-185216b55e9f')
INSERT [dbo].[GroupDefinition] ([GroupDefinitionId], [GroupId], [TagId], [Grouping]) VALUES (22, 7, 5, N'bb656fc1-8ccd-4ff6-85ec-185216b55e9f')
INSERT [dbo].[GroupDefinition] ([GroupDefinitionId], [GroupId], [TagId], [Grouping]) VALUES (23, 7, 6, N'bb656fc1-8ccd-4ff6-85ec-185216b55e9f')
INSERT [dbo].[GroupDefinition] ([GroupDefinitionId], [GroupId], [TagId], [Grouping]) VALUES (24, 7, 2, N'8333dc24-4850-40d9-8b34-86c5d33bca60')
INSERT [dbo].[GroupDefinition] ([GroupDefinitionId], [GroupId], [TagId], [Grouping]) VALUES (25, 7, 5, N'8333dc24-4850-40d9-8b34-86c5d33bca60')
INSERT [dbo].[GroupDefinition] ([GroupDefinitionId], [GroupId], [TagId], [Grouping]) VALUES (26, 7, 6, N'8333dc24-4850-40d9-8b34-86c5d33bca60')
INSERT [dbo].[GroupDefinition] ([GroupDefinitionId], [GroupId], [TagId], [Grouping]) VALUES (27, 8, 1, N'e060b0e9-759f-4fe5-80d8-3fb2a73df6c8')
INSERT [dbo].[GroupDefinition] ([GroupDefinitionId], [GroupId], [TagId], [Grouping]) VALUES (28, 8, 5, N'e060b0e9-759f-4fe5-80d8-3fb2a73df6c8')
INSERT [dbo].[GroupDefinition] ([GroupDefinitionId], [GroupId], [TagId], [Grouping]) VALUES (29, 8, 7, N'e060b0e9-759f-4fe5-80d8-3fb2a73df6c8')
INSERT [dbo].[GroupDefinition] ([GroupDefinitionId], [GroupId], [TagId], [Grouping]) VALUES (30, 8, 2, N'33854572-3081-4e1c-ae98-fa15b2bc86b3')
INSERT [dbo].[GroupDefinition] ([GroupDefinitionId], [GroupId], [TagId], [Grouping]) VALUES (31, 8, 5, N'33854572-3081-4e1c-ae98-fa15b2bc86b3')
INSERT [dbo].[GroupDefinition] ([GroupDefinitionId], [GroupId], [TagId], [Grouping]) VALUES (32, 8, 7, N'33854572-3081-4e1c-ae98-fa15b2bc86b3')
INSERT [dbo].[GroupDefinition] ([GroupDefinitionId], [GroupId], [TagId], [Grouping]) VALUES (33, 9, 3, N'a4bfd6b8-556a-4e01-b3e8-b725a85c458c')
INSERT [dbo].[GroupDefinition] ([GroupDefinitionId], [GroupId], [TagId], [Grouping]) VALUES (34, 9, 4, N'a4bfd6b8-556a-4e01-b3e8-b725a85c458c')
INSERT [dbo].[GroupDefinition] ([GroupDefinitionId], [GroupId], [TagId], [Grouping]) VALUES (35, 9, 6, N'a4bfd6b8-556a-4e01-b3e8-b725a85c458c')
INSERT [dbo].[GroupDefinition] ([GroupDefinitionId], [GroupId], [TagId], [Grouping]) VALUES (36, 10, 6, N'649c0f7a-a5d3-4713-9335-8be57137347e')
INSERT [dbo].[GroupDefinition] ([GroupDefinitionId], [GroupId], [TagId], [Grouping]) VALUES (37, 11, 1, N'54c43caa-67a6-4be3-b237-2a89423360c8')
INSERT [dbo].[GroupDefinition] ([GroupDefinitionId], [GroupId], [TagId], [Grouping]) VALUES (38, 12, 3, N'd282d453-9671-408e-b6c6-d36296369a2e')
Query
DECLARE #employerId INT = 1
IF OBJECT_ID('tempdb..#pivotedEmployeeTags') IS NOT NULL DROP TABLE #pivotedEmployeeTags;
IF OBJECT_ID('tempdb..#pivotedGroupDefinition') IS NOT NULL DROP TABLE #pivotedGroupDefinition;
CREATE TABLE #pivotedEmployeeTags (EmployeeId INT, Name NVARCHAR(50), Country INT NULL, EmployeeType INT NULL, [Language] INT NULL)
CREATE TABLE #pivotedGroupDefinition (GroupId INT, Name NVARCHAR(50), Country INT NULL, EmployeeType INT NULL, [Language] INT NULL)
;WITH FlattenedEmployeeTags AS
(
SELECT
Employee.EmployeeId
,Employee.Name
,Tag.TagId
,Tag.Name as TagName
FROM Employee
LEFT JOIN EmployeeTag ON EmployeeTag.EmployeeId = Employee.EmployeeId
LEFT JOIN Tag ON Tag.TagId = EmployeeTag.TagId
WHERE EmployerId = #employerId
)
INSERT INTO #pivotedEmployeeTags
SELECT
EmployeeId
,Name
,Country = MAX( CASE WHEN TagName = 'Country' THEN TagId END )
,EmployeeType = MAX( CASE WHEN TagName = 'EmployeeType' THEN TagId END )
,[Language] = MAX( CASE WHEN TagName = 'Language' THEN TagId END )
FROM FlattenedEmployeeTags
GROUP BY EmployeeId, Name
;WITH FlattenedGroupDefinition AS
(
SELECT
[Group].GroupId
,[Group].Name
,Tag.TagId
,Tag.Name as TagName
,Grouping
FROM [Group]
LEFT JOIN GroupDefinition ON GroupDefinition.GroupId = [Group].GroupId
LEFT JOIN Tag ON Tag.TagId = GroupDefinition.TagId
WHERE EmployerId = #employerId
)
INSERT INTO #pivotedGroupDefinition
SELECT
GroupId
,Name
,Country = MAX( CASE WHEN TagName = 'Country' THEN TagId END )
,EmployeeType = MAX( CASE WHEN TagName = 'EmployeeType' THEN TagId END )
,[Language] = MAX( CASE WHEN TagName = 'Language' THEN TagId END )
FROM FlattenedGroupDefinition
GROUP BY GroupId, Name, Grouping
ORDER BY GroupId, Grouping
SELECT
EmpTags.EmployeeId
, GrpTags.GroupId
FROM
#pivotedEmployeeTags EmpTags
INNER JOIN #pivotedGroupDefinition GrpTags
ON
(GrpTags.Country = EmpTags.Country OR GrpTags.Country IS NULL)
AND (GrpTags.EmployeeType = EmpTags.EmployeeType OR GrpTags.EmployeeType IS NULL)
AND (GrpTags.[Language] = EmpTags.[Language] OR GrpTags.[Language] IS NULL)
ORDER BY EmpTags.EmployeeId, GrpTags.GroupId
I have been struggling with this query for weeks now, making various db changes to help make the query work correctly.
This is my continuing survey task.
The last task is to display results of surey taken by any individual.
The query is to list the each multiple choice question, followed by user's choice and the correct answer or answers depending on whether the question is checkbox question that takes more than answers as correct answers.
Then the next row is compute total questions answered, how many the user got right out of total answered and percentage of correct answers.
Here is the general layout:
Question Your Choice Correct Answer
Total Questions:_________ You got _X out of _X number %Correct:____x%
Because of the complexity, I have broken the sql query into 3. The first query list each query. The second lists users choices and the third lists correct answers.
All filtered by SurveyId and Username
So far this is fine.
The area I am having the most difficulty is computing Total Questions, how many user got out of total questions and percentage.
Below is my query. I am supposed to give a demo of this survey this afternoon.
I hope you generous SQL geniuses can bail me out.
SELECT Q.QUESTION,
Sum(CASE
WHEN A.CHOICEID IS NOT NULL
AND C.ISCORRECT = 'True' THEN 1
ELSE 0
END - CASE
WHEN Q.ANSWERTYPE = 'M'
AND A.CHOICEID IS NOT NULL
AND C.ISCORRECT = 'False' THEN 1
ELSE 0
END) / ( CASE Q.ANSWERTYPE
WHEN 'S' THEN 1
WHEN 'M' THEN Sum(CASE
WHEN C.ISCORRECT = 'True' THEN 1
ELSE 0
END)
END ) AS score
FROM SURVEYQUESTIONS AS Q
INNER JOIN SURVEY AS S
ON Q.SURVEYID = S.SURVEYID
INNER JOIN SURVEYCHOICES AS C
ON Q.QUESTIONID = C.QUESTIONID
LEFT JOIN SURVEYANSWERS AS A
ON A.QUESTIONID = C.QUESTIONID
LEFT JOIN SURVEYANSWERS AS sa
ON C.CHOICEID = A.CHOICEID
AND A.USERNAME = #UserName
WHERE S.SURVEYID = #SurveyId
GROUP BY Q.QUESTION,
Q.ANSWERTYPE;
I will be happy to post table structures if needed.
Thanks a lot in advance
Your SQLFiddle example only had one survey answer which wasn't part of survey 10. I have added one correct answer to the new SQL Fiddle. I think the query at the end gets you what you want and is very simple.
SQL Fiddle details below:
SQL Fiddle
MS SQL Server 2008 Schema Setup:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[SurveyQuestions]') AND type in (N'U'))
BEGIN
CREATE TABLE [dbo].[SurveyQuestions](
[QuestionID] [int] IDENTITY(1,1) NOT NULL,
[SurveyID] [int] NULL,
[Question] [varchar](255) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
[AnswerType] [char](1) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
[QuestionOrder] [int] NULL,
CONSTRAINT [PK_SurveyQuestions_1] PRIMARY KEY CLUSTERED
(
[QuestionID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
)
END
GO
SET IDENTITY_INSERT [dbo].[SurveyQuestions] ON
INSERT [dbo].[SurveyQuestions] ([QuestionID], [SurveyID], [Question], [AnswerType], [QuestionOrder]) VALUES (8, 10, N'Archaeological studies of the Indus Valley cities of Harappa and Mohenjo-Daro show evidence of.', N'S', 1)
INSERT [dbo].[SurveyQuestions] ([QuestionID], [SurveyID], [Question], [AnswerType], [QuestionOrder]) VALUES (9, 10, N'Between 1540 and 1580, what happened to the native population of Central Mexico?', N'M', 2)
INSERT [dbo].[SurveyQuestions] ([QuestionID], [SurveyID], [Question], [AnswerType], [QuestionOrder]) VALUES (11, 9, N'What is Avalon?', N'S', 1)
INSERT [dbo].[SurveyQuestions] ([QuestionID], [SurveyID], [Question], [AnswerType], [QuestionOrder]) VALUES (13, 8, N'What is your quest?', N'S', 2)
INSERT [dbo].[SurveyQuestions] ([QuestionID], [SurveyID], [Question], [AnswerType], [QuestionOrder]) VALUES (14, 11, N'How do you like this video', N'S', 1)
INSERT [dbo].[SurveyQuestions] ([QuestionID], [SurveyID], [Question], [AnswerType], [QuestionOrder]) VALUES (15, 11, N'Your favorite movie', N'M', 2)
INSERT [dbo].[SurveyQuestions] ([QuestionID], [SurveyID], [Question], [AnswerType], [QuestionOrder]) VALUES (16, 10, N'George Boole is a:', N'M', 3)
SET IDENTITY_INSERT [dbo].[SurveyQuestions] OFF
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[Survey]') AND type in (N'U'))
BEGIN
CREATE TABLE [dbo].[Survey](
[SurveyID] [int] IDENTITY(1,1) NOT NULL,
[Title] [varchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
[Description] [varchar](max) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
CONSTRAINT [PK_Survey] PRIMARY KEY CLUSTERED
(
[SurveyID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
)
END
GO
SET IDENTITY_INSERT [dbo].[Survey] ON
INSERT [dbo].[Survey] ([SurveyID], [Title], [Description]) VALUES (8, N'The Bridge of Death', N'Test your knowledge of this classic scene from a classic movie.')
INSERT [dbo].[Survey] ([SurveyID], [Title], [Description]) VALUES (9, N'What''s Next at Microsoft?', N'Reading your blogs? Test your knowledge about what''s baking in Microsoft''s oven.')
INSERT [dbo].[Survey] ([SurveyID], [Title], [Description]) VALUES (10, N'Movie History', N'Test your knowledge of movies')
SET IDENTITY_INSERT [dbo].[Survey] OFF
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[SurveyChoices]') AND type in (N'U'))
BEGIN
CREATE TABLE [dbo].[SurveyChoices](
[ChoiceID] [int] IDENTITY(1,1) NOT NULL,
[QuestionID] [int] NOT NULL,
[Choice] [nvarchar](255) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
[IsCorrect] [bit] NULL,
CONSTRAINT [PK_SurveyChoices] PRIMARY KEY CLUSTERED
(
[ChoiceID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
)
END
GO
SET IDENTITY_INSERT [dbo].[SurveyChoices] ON
INSERT [dbo].[SurveyChoices] ([ChoiceID], [QuestionID], [Choice], [IsCorrect]) VALUES (56, 8, N'dynastic rule', 1)
INSERT [dbo].[SurveyChoices] ([ChoiceID], [QuestionID], [Choice], [IsCorrect]) VALUES (57, 8, N'monotheism', 0)
INSERT [dbo].[SurveyChoices] ([ChoiceID], [QuestionID], [Choice], [IsCorrect]) VALUES (58, 8, N'social equality', 0)
INSERT [dbo].[SurveyChoices] ([ChoiceID], [QuestionID], [Choice], [IsCorrect]) VALUES (59, 8, N'urban planning', 0)
INSERT [dbo].[SurveyChoices] ([ChoiceID], [QuestionID], [Choice], [IsCorrect]) VALUES (60, 9, N'It decreased by approximately 6 million people.', 0)
INSERT [dbo].[SurveyChoices] ([ChoiceID], [QuestionID], [Choice], [IsCorrect]) VALUES (61, 9, N'It increased to a high of 26 million people.', 0)
INSERT [dbo].[SurveyChoices] ([ChoiceID], [QuestionID], [Choice], [IsCorrect]) VALUES (62, 9, N'It increased by approximatley 2 million people per year.', 1)
INSERT [dbo].[SurveyChoices] ([ChoiceID], [QuestionID], [Choice], [IsCorrect]) VALUES (63, 9, N'It decreased to 8 million people.', 1)
INSERT [dbo].[SurveyChoices] ([ChoiceID], [QuestionID], [Choice], [IsCorrect]) VALUES (64, 11, N'Build UI with XAML', 0)
INSERT [dbo].[SurveyChoices] ([ChoiceID], [QuestionID], [Choice], [IsCorrect]) VALUES (65, 11, N'Next Generation Web Services', 1)
INSERT [dbo].[SurveyChoices] ([ChoiceID], [QuestionID], [Choice], [IsCorrect]) VALUES (66, 11, N'Next Version of Office', 0)
INSERT [dbo].[SurveyChoices] ([ChoiceID], [QuestionID], [Choice], [IsCorrect]) VALUES (67, 11, N'Codename for Xbox 360', 0)
INSERT [dbo].[SurveyChoices] ([ChoiceID], [QuestionID], [Choice], [IsCorrect]) VALUES (89, 13, N'To seek the Holy Grail', 1)
INSERT [dbo].[SurveyChoices] ([ChoiceID], [QuestionID], [Choice], [IsCorrect]) VALUES (90, 13, N'To seek the Holy Hand Grenade', 0)
INSERT [dbo].[SurveyChoices] ([ChoiceID], [QuestionID], [Choice], [IsCorrect]) VALUES (91, 13, N'To see the Knight that says Ni!', 0)
INSERT [dbo].[SurveyChoices] ([ChoiceID], [QuestionID], [Choice], [IsCorrect]) VALUES (92, 13, N'To sing the Ballad of Brave Sir Robin', 0)
INSERT [dbo].[SurveyChoices] ([ChoiceID], [QuestionID], [Choice], [IsCorrect]) VALUES (93, 14, N'Bad', 0)
INSERT [dbo].[SurveyChoices] ([ChoiceID], [QuestionID], [Choice], [IsCorrect]) VALUES (94, 14, N'Ok', 0)
INSERT [dbo].[SurveyChoices] ([ChoiceID], [QuestionID], [Choice], [IsCorrect]) VALUES (95, 14, N'Good', 0)
INSERT [dbo].[SurveyChoices] ([ChoiceID], [QuestionID], [Choice], [IsCorrect]) VALUES (97, 14, N'Excellent', 1)
SET IDENTITY_INSERT [dbo].[SurveyChoices] OFF
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[SurveyAnswers]') AND type in (N'U'))
BEGIN
CREATE TABLE [dbo].[SurveyAnswers](
[AnswerID] [int] IDENTITY(1,1) NOT NULL,
[QuestionID] [int] NOT NULL,
[ChoiceID] [int] NULL,
[ChoiceText] [varchar](max) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
[UserName] [varchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
CONSTRAINT [PK_SurveyAnswers] PRIMARY KEY CLUSTERED
(
[AnswerID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
)
END
GO
SET IDENTITY_INSERT [dbo].[SurveyAnswers] ON
INSERT [dbo].[SurveyAnswers] ([AnswerID], [QuestionID], [ChoiceID], [ChoiceText], [UserName]) VALUES (51, 14, 95, NULL, N'John.Doe')
INSERT [dbo].[SurveyAnswers] ([AnswerID], [QuestionID], [ChoiceID], [ChoiceText], [UserName]) VALUES (52, 9, 62, NULL, N'John.Doe')
SET IDENTITY_INSERT [dbo].[SurveyAnswers] OFF
Query 1:
SELECT SUM(CASE WHEN SC.IsCorrect = 1 THEN 1 ELSE 0 END) AS TotalQuestions,
COUNT(SA.AnswerID) AS TotalCorrect,
CAST(COUNT(SA.AnswerID) AS Float) /
SUM(CASE WHEN SC.IsCorrect = 1 THEN 1 ELSE 0 END) * 100 As Percentage
FROM
SurveyQuestions SQ
INNER JOIN SurveyChoices SC
ON SQ.QuestionId = SC.QuestionID
LEFT JOIN SurveyAnswers SA
ON SA.QuestionId = SC.QuestionID
AND SA.ChoiceID = SC.ChoiceID
AND SA.UserName = 'John.Doe'
WHERE SC.IsCorrect = 1
AND SQ.SurveyID = 10
Results:
| TOTALQUESTIONS | TOTALCORRECT | PERCENTAGE |
---------------------------------------------------
| 3 | 1 | 33.333333333333 |
I've tried to give you some idea on how it could be done, though I'm not exactly sure about the column names and resulting column:
with SingleAnswers (QuestionID,SurveyID,Username,TotalSingle)
as(
Select
SQ.QuestionID,S.SurveyID, Username,count(*)TotalSingle
from
SurveyAnswers SA
join
surveychoices SC on SA.choiceId = SC.choiceId
join
surveyquestions SQ on SQ.QuestionID = SC.QuestionID
JOIN
Survey S ON SQ.SurveyID = S.SurveyID
where
SA.ChoiceID is Not Null and username = #UserName and SC.iscorrect='True' and SQ.AnswerType='S'
group by
SQ.QuestionID,S.SurveyID, Username)
,MultipleAnswers (QuestionID,SurveyID,Username,TotalMultiple)
as(
Select
SQ.QuestionID,S.SurveyID, Username,count(*)TotalMultiple
from
SurveyAnswers SA
join
surveychoices SC on SA.choiceId = SC.choiceId
join
surveyquestions SQ on SQ.QuestionID = SC.QuestionID
JOIN
Survey S ON SQ.SurveyID = S.SurveyID
where
SA.ChoiceID is Not Null and username = #UserName and SC.iscorrect='True' and SQ.AnswerType='M'
group by
SQ.QuestionID,S.SurveyID, Username)
select
count(Q.QuestionID) TotalQuestions,'You got '+Convert(Varchar,sum(TotalSingle) +sum(TotalMultiple))+'out of '+Convert(Varchar,count(Q.QuestionID))+' number' FinalOutCome,(count(Q.QuestionID)/sum(TotalSingle)+sum(TotalMultiple)) Correct_Percent
from
surveyquestions AS Q
JOIN
Survey AS S ON Q.SurveyID = S.SurveyID
LEFT JOIN
SingleAnswers SA ON SA.QuestionID = Q.QuestionID AND SA.SurveyID = S.SurveyID
LEFT JOIN
MultipleAnswers MA ON MA.QuestionID = Q.QuestionID AND SA.SurveyID = S.SurveyID