How To Improve Performance of Sql Query with Union - sql

Below query takes almost 47-50 seconds on our production server, but when I execute the same on a test server with the same database, it executes in less than a second.
CREATE TABLE [dbo].[Table0]
(
[UserID] [VARCHAR](20) NOT NULL,
[Key] [VARCHAR](600) NOT NULL,
[Type] [VARCHAR](20) NOT NULL,
[status] [VARCHAR](10) NOT NULL,
[RecID] [NUMERIC](18, 0) NOT NULL,
CONSTRAINT [PK_Table0]
PRIMARY KEY CLUSTERED ([UserID] ASC, [Key] ASC, [Type] ASC, [status], [RecID] ASC)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
CREATE TABLE [dbo].[Table2]
(
[UserID] [VARCHAR](20) NOT NULL,
[RecID] [NUMERIC](18, 0) NOT NULL,
[Activity] [NUMERIC](2, 0) NOT NULL,
[AwsExist] [NUMERIC](2, 0) NULL,
[View] [NUMERIC](2, 0) NULL,
CONSTRAINT [PK_Table2]
PRIMARY KEY CLUSTERED ([UserID] ASC, [RecID] ASC, [Activity] ASC)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
CREATE TABLE [dbo].[Table3]
(
[UserID] [VARCHAR](20) NOT NULL,
[RecId] [NUMERIC](18, 0) NOT NULL,
[Activity] [NUMERIC](2, 0) NOT NULL,
[AwsExist] [NUMERIC](2, 0) NULL,
[RecDate] [DATETIME] NULL,
[View] [NUMERIC](2, 0) NULL,
CONSTRAINT [PK_Table3]
PRIMARY KEY CLUSTERED ([UserID] ASC, [RecId] ASC, [Activity] ASC)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
Table0 contains 10,000 Records
Table1 contains 20,00,000 records
Table2 contains 25,00,000 records
which parameter should I check to resolve the issue? I just want to check if a record exists in one of these table for RecID
Select UserID From Table0 Where RecId = 56445 And Type = 'D'
Union
Select UserID From Table1 Where RecId = 56445 And View = 0
Union
Select UserID From Table2 Where RecId = 56445 And View = 0
I tried with this code:
DECLARE RecID AS INT
SET RecID = 56445
IF NOT EXISTS (SELECT DISTINCT TOP(1) USerID
FROM Table0
WHERE RecId = #RecID
AND Type = 'D')
BEGIN
IF NOT EXISTS (SELECT DISTINCT TOP(1) UserID
FROM Table1
WHERE RecId = #RecID AND View = 0)
BEGIN
SELECT DISTINCT TOP(1) UserID
FROM Table2
WHERE RecId = #RecID AND View = 0
END
END
but it also takes around 18 seconds.

This query should be fast -- assuming not many rows are returned:
Select UserID From Table0 Where RecId = 56445 And Type = 'D'
Union
Select UserID From Table1 Where RecId = 56445 And View = 0
Union
Select UserID From Table2 Where RecId = 56445 And View = 0;
What you need are indexes:
Table0(recid, type, userid)
Table1(recid, view, userid)
Table2(recid, view, userid)

You may have to use query like:
Select UserID
From table0
Where exists (
Select 1
From Table0 t0, Table1 t1, Table2 t2
Where (t0.RecId = 56445 and t0.Type= 'D') OR (t1.RecId = 56445 and t1.View= 0) OR (t2.RecId = 56445 AND t2.View=0))

Related

Why calculated fields using scalar functions are slow

I have below table:
CREATE TABLE [dbo].[Client](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](150) NOT NULL,
[InternalSiteId] AS (isnull(CONVERT([int],[dbo].[GetCurrentTemporalValue]([Id],'Client_InternalSite')),(0))),
[BudgetingStatusId] AS (isnull(CONVERT([int],[dbo].[GetCurrentTemporalValue]([Id],'Client_BudgetingStatus')),(1))),
[BusinessUnitId] AS (isnull(CONVERT([int],[dbo].[GetCurrentTemporalValue]([Id],'Client_BusinessUnit')),(0))),
CONSTRAINT [PK_dbo.Client] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
which has 3 calculated fields using scalar function:
CREATE FUNCTION [dbo].[GetCurrentTemporalValue]
(
#clientId INT,
#temporalType NVARCHAR(128)
)
RETURNS NVARCHAR(255)
AS
BEGIN
DECLARE #retVal INT
DECLARE #at DATETIME
SET #at = GETUTCDATE()
SELECT #retVal = CAST(Value AS INT) FROM dbo.Temporal
WHERE 1 = 1
AND ClientId = #clientId
AND TemporalType = #temporalType
AND ( ValidFrom <= #at OR ValidFrom IS NULL )
AND ( ValidTo >= #at OR ValidTo IS NULL)
RETURN #retVal
END
GO
and this function uses below table:
CREATE TABLE [dbo].[Temporal](
[Id] [int] IDENTITY(1,1) NOT NULL,
[ClientId] [int] NOT NULL,
[Value] [nvarchar](255) NULL,
[ValidFrom] [datetime2](7) NULL,
[ValidTo] [datetime2](7) NULL,
[TemporalType] [nvarchar](128) NOT NULL,
CONSTRAINT [PK_dbo.Temporal] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO
The Client table has around 2500 records but the select * from [Client] takes about 14 seconds!
When I comment these 3 calculated fields, it gets back to normal value below one second. So the scalar function seems to cause the issue.
I tried to make condition easier ( left only 1 = 1 ) but it didn't change the speed.
What I want to achieve is:
historical values (kept in Temporal table)
current value to be pointed out by Client.InternalSiteId, Client.BudgetingStatusId and Client.BusinessUnitId
I cannot just simply make InternalSiteId a regular int fields with foreign key to, let say, InternalSiteHistoryTable as there are ValidFrom and ValidTo fields pointing out the period in which given value is valid and current and e.g. ValidFrom can be set to future value. That's why I need such calculations in function to find out current value.
What should I do / change to achieve above goals, but keep the reasonable fetching data speed?
Use a view to join to your Temporal table instead of embedding function calls
-- Table without those functions to slow things down
CREATE TABLE [dbo].[ClientName](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](150) NOT NULL,
CONSTRAINT [PK_dbo.Client] PRIMARY KEY CLUSTERED
(
[Id] ASC
) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF)
ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
--instead, use a view to do the same thing
CREATE VIEW [dbo].[Client] as
SELECT
ClientName.Id,
ClientName.Name,
isnull(CONVERT([int], Client_InternalSite.Value), 0) AS InternalSiteId,
isnull(CONVERT([int], Client_BudgetingStatus.Value, 1) AS BudgetingStatusId,
isnull(CONVERT([int], Client_BusinessUnit.Value, 0) AS BusinessUnitId
FROM ClientName INNER JOIN
( SELECT Value, ClientId
FROM Temporal
WHERE TemporalType='Client_InternalSite'
AND ( ValidFrom <= GETUTCDATE() OR ValidFrom IS NULL )
AND ( ValidTo >= GETUTCDATE() OR ValidTo IS NULL)
) AS Client_InternalSite ON ClientName.ID = Client_InternalSite.ClientID
INNER JOIN
( SELECT Value, ClientId
FROM Temporal
WHERE TemporalType='Client_BudgetingStatus'
AND ( ValidFrom <= GETUTCDATE() OR ValidFrom IS NULL )
AND ( ValidTo >= GETUTCDATE() OR ValidTo IS NULL)
) AS Client_BudgetingStatus ON ClientName.ID = Client_BudgetingStatus.ClientID
INNER JOIN
( SELECT Value, ClientId
FROM Temporal
WHERE TemporalType='Client_BusinessUnit'
AND ( ValidFrom <= GETUTCDATE() OR ValidFrom IS NULL )
AND ( ValidTo >= GETUTCDATE() OR ValidTo IS NULL)
) AS Client_BusinessUnit ON ClientName.ID = Client_BusinessUnit.ClientID
GO
I can't test this against your DB, so I don't know about your indexes on your Temporal table (ID, ValidFrom, ValidTo columns), but typically a VIEW like this is going to run quicker because the tables are queried only once.

SQL Descending ordered LEFT JOIN subquery issue

I have the following query.
SELECT r1.*,
r2.vlag54,
r2.vlag55
FROM [rxmon].[dbo].[a] AS r1
LEFT JOIN [rxmon].[dbo].[b] AS r2
ON r2.artikelnummer = r1.drug_id
LEFT JOIN (SELECT *
FROM [rxmon].[dbo].[c]) AS r3
ON r3.pid = r1.patient_id
WHERE r3.obx_id = 20937
AND Cast(r3.obx_datetime AS DATE) = Cast(Getdate() - 1 AS DATE)
AND r1.patient_id = 7092425
AND obx_value < CASE
WHEN r2.vlag54 = 1 THEN 30
WHEN r2.vlag55 = 1 THEN 50
END
AND r2.vlag54 = CASE
WHEN r3.obx_value < 30 THEN 1
ELSE 0
END
AND r2.vlag55 = CASE
WHEN r3.obx_value BETWEEN 30 AND 50 THEN 1
ELSE 0
END
ORDER BY obx_datetime DESC;
The problem is that table C can contain multiple records based on de PID join. This generates the same records because of the multiple records on table C.
The table C needs to e joined as the latest record only so just 1 of C. That way the table A record will not be repeated.
I tried TOP 1 and order by but that can't be used in subquery.
-- TABLE A
CREATE TABLE [dbo].[A]
[EVS_MO_ID] [bigint] NOT NULL,
[DRUG_ID] [varchar](50) NOT NULL,
[ATC_CODE] [varchar](15) NULL,
[DRUG_NAME] [varchar](1024) NULL,
[PATIENT_ID] [varchar](50) NOT NULL,
[PATIENT_LOCATION] [varchar](10) NULL,
[MO_DATE] [datetime2](7) NOT NULL,
[MO_START_DATE] [datetime2](7) NOT NULL,
[MO_STOP_DATE] [datetime2](7) NULL,
[ROUTE] [varchar](50) NULL,
[MEDICATION_CONTAINER] [smallint] NULL,
[PRESCRIBING_DOCTOR_NAME] [varchar](50) NULL,
[PRESCRIBING_DOCTOR_SURNAME] [varchar](50) NULL,
[MO_ACTIVE] [bit] NOT NULL,
CONSTRAINT [PK_MedicationOrders] PRIMARY KEY CLUSTERED
(
[EVS_MO_ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = ON, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
INSERT INTO [dbo].[A]
VALUES
(5411409,'97941689', 'B01AB06','NADROPARINE 0.8ML','7092425','ANBC', '2015-12-15 20:58:06.2030000',
'2015-12-16 00:00:00.0000000', '', 'IV', 1, 'GEORGE','LAST', 1);
-- TABLE B
CREATE TABLE [dbo].[B](
[ID] [int] IDENTITY(1,1) NOT NULL,
[ARTIKELNUMMER] [varchar](50) NOT NULL,
[VLAG54] [bit] NULL,
[VLAG55] [bit] NULL CONSTRAINT [DF_Table_1_VLAG50] DEFAULT ((0)),
[VLAG100] [bit] NULL CONSTRAINT [DF_ArtikelVlaggen_VLAG100] DEFAULT ((0)),
CONSTRAINT [PK_B] PRIMARY KEY CLUSTERED
(
[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]
INSERT INTO [dbo].[B]
([ARTIKELNUMMER]
,[VLAG54]
,[VLAG55]
,[VLAG100])
VALUES
('97941689', 1,0,1);
-- TABLE C
CREATE TABLE [dbo].[C](
[ID] [int] IDENTITY(1,1) NOT NULL,
[OBX_DATETIME] [datetime2](7) NOT NULL,
[PID] [int] NOT NULL,
[DEPARTMENT] [varchar](8) NOT NULL,
[OBX_ID] [int] NOT NULL,
[OBX_VALUE] [decimal](5, 2) NOT NULL,
[OBX_UNITS] [varchar](10) NULL,
[REF_RANGE] [varchar](40) NULL,
[FLAG] [varchar](2) NULL,
CONSTRAINT [PK_C] PRIMARY KEY CLUSTERED
(
[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]
INSERT INTO [dbo].[C]
([OBX_DATETIME]
,[PID]
,[DEPARTMENT]
,[OBX_ID]
,[OBX_VALUE]
,[OBX_UNITS]
,[REF_RANGE]
,[FLAG])
VALUES
('2015-12-15 14:01:00.0000000',7092425, '8NAH', 20937, 27.00, 'mL/min', '> 60', 'L');
INSERT INTO [dbo].[C]
([OBX_DATETIME]
,[PID]
,[DEPARTMENT]
,[OBX_ID]
,[OBX_VALUE]
,[OBX_UNITS]
,[REF_RANGE]
,[FLAG])
VALUES
('2015-12-15 06:30:00.0000000',7092425, '6ZPA', 20937, 28.00, 'mL/min', '> 60', 'L');
This will order them by OBX_DATETIME and take only the first one:
...
LEFT JOIN (
SELECT pid, obx_id, obx_datetime, obx_value
, n = ROW_NUMBER() over(PARTITION BY pid ORDER BY obx_datetime desc)
FROM [rxmon].[dbo].[c]
) AS r3
ON r3.pid = r1.patient_id and r3.n = 1
...
If OBX_DATETIME are inserted incrementaly (newer date only), you can order by ID instead.
This SQL Fiddle with your query and sample data/tables returns 2 rows: http://sqlfiddle.com/#!3/df36c/2/0
This SQL Fiddle with the new subquery returns 1 row: http://sqlfiddle.com/#!3/df36c/1/0
You are using a LEFT JOIN on r3 but have also have r3 in your WHERE clause with equal operator:
WHERE r3.obx_id = 20937
AND Cast(r3.obx_datetime AS DATE) = Cast(Getdate() - 1 AS DATE)
It will remove NULL value from the left join on r3. Perhaps you should also move it to the sub query or use INNER JOIN.
You should also avoind using the DB name in your query unless this query is run from another DB on the same server. This will be fine:
SELECT ... FROM [dbo].[a] AS r1 ...
Using SELECT * is also a bad habit. You should list only the columns your code will use.
try this.... #Shift
SELECT r1.*,
r2.vlag54,
r2.vlag55
FROM [dbo].[a] AS r1
LEFT JOIN [dbo].[b] AS r2
ON r2.artikelnummer = r1.drug_id
LEFT JOIN (
SELECT
ROW_NUMBER() OVER (PARTITION BY pid ORDER BY id DESC) RN,
c.*
FROM C
) r3
ON r3.pid = r1.patient_id AND r3.RN = 1
WHERE r3.obx_id = 20937
AND Cast(r3.obx_datetime AS DATE) = Cast(Getdate() - 1 AS DATE)
AND r1.patient_id = 7092425
AND obx_value < CASE
WHEN r2.vlag54 = 1 THEN 30
WHEN r2.vlag55 = 1 THEN 50
END
AND r2.vlag54 = CASE
WHEN r3.obx_value < 30 THEN 1
ELSE 0
END
AND r2.vlag55 = CASE
WHEN r3.obx_value BETWEEN 30 AND 50 THEN 1
ELSE 0
END
ORDER BY obx_datetime DESC;

What is the optimal select according to you?

What is the optimal select according to you?
select #MailTo=ISNULL((select data from filedata where descid=3104 and DataId=evt04) ,'')
from event_21
where evtid=#nFileId
or
select #MailTo=ISNULL(data ,'')
from event_21
innerjoin filedata on event_21.evt04=filedata.dataid
where descid=3104
and evtid=#nFileId
Obviously "join" is faster than "inline select query". I have tested with 1000 rows. You can also test. here is the sample test code.
CREATE TABLE [dbo].[tableA](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](100) NOT NULL,
CONSTRAINT [PK_tableA] PRIMARY KEY CLUSTERED
(
[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
CREATE TABLE [dbo].[tableB](
[RowId] [int] IDENTITY(1,1) NOT NULL,
[Id] [int] NOT NULL,
[Designation] [nvarchar](100) NULL,
CONSTRAINT [PK_tableB] PRIMARY KEY CLUSTERED
(
[RowId] 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
Declare #Min Int = 1
,#Max Int = 1000
While (#Min <= #Max)
Begin
Insert Into tableA(Name)
Select 'Name would be the name of - ' + Cast(#Min As Nvarchar(10))
Insert Into tableB(Id,Designation)
Select #Min
,'Desig could be the name of - Name' + Cast(#Min As Nvarchar(10))
Select #Min = #Min + 1
End
First look # inline select query
-- inline query
Select a.Id
,a.Name
,(Select Designation From tableB As b Where b.Id = a.Id) As Designation
From tableA As a With (Nolock)
output:
Execution Plan:
now the Join query :-
---- join
Select a.Id
,a.Name
,b.Designation
From tableA As a With (Nolock)
Join tableB As b On a.Id = b.Id
execution plan for join query :-
you can see the clear difference.

SQL Server 2008 Trigger to Update/Insert/Delete From Multiple Tables

I have a table UserInfoComputed whose data comes from UserInfo and UserInfoComputed also have foreign key constraint to UserCompany.
I have a trigger on UserInfo which inserts/updates/deletes rows into UserInfoComputed
Here is my UserInfoComputed table:
CREATE TABLE [dbo].[UserInfoComputed ](
[id] AS (CONVERT([bigint],replace([law_id],'LAW',''),(0))) PERSISTED NOT NULL,
[company_id] [varchar](12) NOT NULL,
[first_name] [varchar](30) NOT NULL,
[last_name] [varchar](30) NOT NULL,
[law_id] [varchar](12) NOT NULL,
[type] [smallint] NULL,
[dtype] AS (case [TYPE] when (1) then 'Corporate' else 'Non-Corporate' end) PERSISTED NOT NULL,
CONSTRAINT [PK_UserInfoComputed] PRIMARY KEY CLUSTERED
(
[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
ALTER TABLE [dbo].[UserInfoComputed] WITH CHECK ADD CONSTRAINT [FK668581C04AA07B12] FOREIGN KEY([company_id])
REFERENCES [dbo].[UserCompany] ([id])
GO
Here is my UserInfo table
CREATE TABLE [dbo].[UserInfo](
[ID] [varchar](12) NOT NULL,
[CompanyID] [varchar](12) NULL,
[Status] [char](4) NULL,
[FirstName] [varchar](30) NOT NULL,
[LastName] [varchar](30) NOT NULL,
CONSTRAINT [PK_UserInfo] PRIMARY KEY CLUSTERED
(
[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] TEXTIMAGE_ON [PRIMARY]
GO
Here is the UserCompany table
CREATE TABLE [dbo].[UserCompany](
[ID] [varchar](12) NOT NULL,
[Name] [varchar](100) NULL,
[ShortName] [varchar](25) NULL,
[Type] [smallint] NULL,
CONSTRAINT [PK_UserCompany] PRIMARY KEY NONCLUSTERED
(
[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
The type values are either 1 or 2 or 3
Here is my trigger on UserInfo table
CREATE TRIGGER [dbo].[ReconcileUserInfoComputed]
ON [dbo].[UserInformation]
AFTER INSERT,DELETE,UPDATE
AS
IF ##ROWCOUNT = 0 -- exit trigger when zero records affected
BEGIN
RETURN
END
IF EXISTS (SELECT * FROM INSERTED)
BEGIN
IF EXISTS (SELECT * FROM DELETED)
BEGIN
--UPDATE
UPDATE [dbo].[UserInformationComputed]
SET -- use new values from inserted
first_name = (SELECT FirstName FROM inserted),
last_name = (SELECT LastName FROM inserted),
law_id = (SELECT ID FROM inserted)
WHERE law_id = (SELECT ID FROM deleted)
END
ELSE
BEGIN
--INSERT
INSERT INTO [dbo].[UserInfoComputed] (first_name,last_name, law_id)
SELECT FirstName, LastName, ID FROM inserted
END
END
ELSE IF EXISTS(SELECT * FROM DELETED)
BEGIN
--DELETE
DELETE FROM [dbo].[UserInfoComputed]
WHERE law_id = (SELECT id FROM deleted)
END
GO
Is there a way to insert or update type value from UserCompany into UserInfoComputed table in ReconcileUserInfoComputed trigger?

Figure Out Which OrderIDs are 0$ Payment Totals

I am in need to some help writing a SQL 2012 query that will help me find and mark orderID's that are a $0.00 payments due to reversal(s)
So far I have:
Select Distinct a.orderID, a.orderPaid,
(Select SUM((c1.linePrice + c1.lineShippingCost + c1.lineTaxCost + c1.lineOptionCost) * c1.lineQuantity)
From vwSelectOrderLineItems c1 Where c1.orderID = a.orderID) As OrderAmount,
(Select SUM(b1.payAmount) FROM vwSelectOrderPayments b1 Where b1.orderID = a.orderID) as Payment,
1 As IsReversal
From vwSelectOrders a
Left Outer Join vwSelectOrderPayments b On b.orderID = a.orderID
Where b.payValid = 1 AND a.orderPaid = 0
Which is returning me some $0 payments on some orders. When I query that payment table with the orderID of these records, I can see that 2 payments were posted... 1 the original payment, 2 the reversal.
How Can I flag the Orders that are $0 payments?
Oders
CREATE TABLE [dbo].[TblOrders](
[orderID] [bigint] IDENTITY(1000,1) NOT NULL,
[orderPaid] [bit] NOT NULL,
[orderPaidOn] [datetime] NULL
CONSTRAINT [PK_TblOrders] PRIMARY KEY CLUSTERED
(
[orderID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 50) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
ALTER TABLE [dbo].[TblOrders] ADD CONSTRAINT [DF__TblOrders__order__1975C517] DEFAULT ((0)) FOR [orderPaid]
Order Line Items
CREATE TABLE [dbo].[TblOrderLineItems](
[lineID] [bigint] IDENTITY(1,1) NOT NULL,
[orderID] [bigint] NOT NULL,
[lineQuantity] [int] NOT NULL,
[linePrice] [money] NOT NULL,
[lineShippingCost] [money] NOT NULL,
[lineTaxCost] [money] NOT NULL,
[lineOptionCost] [money] NOT NULL,
CONSTRAINT [PK_TblOrderLineItems] PRIMARY KEY CLUSTERED
(
[lineID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 50) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
ALTER TABLE [dbo].[TblOrderLineItems] ADD CONSTRAINT [DF_TblOrderLineItems_lineShippingCost] DEFAULT ((0)) FOR [lineShippingCost]
GO
ALTER TABLE [dbo].[TblOrderLineItems] ADD CONSTRAINT [DF_TblOrderLineItems_lineTaxCost] DEFAULT ((0)) FOR [lineTaxCost]
GO
ALTER TABLE [dbo].[TblOrderLineItems] ADD CONSTRAINT [DF_TblOrderLineItems_lineOptionCost] DEFAULT ((0)) FOR [lineOptionCost]
GO
Order Payments
CREATE TABLE [dbo].[TblOrderPayments](
[paymentID] [bigint] IDENTITY(1,1) NOT NULL,
[orderID] [bigint] NOT NULL,
[payAmount] [money] NOT NULL,
[payPosted] [datetime] NOT NULL,
[payValid] [bit] NOT NULL,
CONSTRAINT [PK_TblOrderPayments] PRIMARY KEY CLUSTERED
(
[paymentID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 50) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
ALTER TABLE [dbo].[TblOrderPayments] ADD CONSTRAINT [DF_TblOrderPayments_payValid] DEFAULT ((0)) FOR [payValid]
GO
Views
CREATE VIEW [dbo].[vwSelectOrderLineItems] AS
SELECT linePrice, lineShippingCost, lineTaxCost, lineOptionCost, lineQuantity
FROM [dbo].[TblOrderLineItems]
CREATE VIEW [dbo].[vwSelectOrderPayments] AS
SELECT paymentID, orderID, payAmount, payValid
FROM dbo.TblOrderPayments
CREATE VIEW [dbo].[vwSelectOrders] AS
SELECT orderID , orderPaid
FROM dbo.TblOrders
Note
I cannot change the table structure
SELECT distinct a.orderid,
a.orderPaid,
c.OrderAmount
d.Payment
From vwSelectOrders AS a
INNER JOIN ( Select SUM((linePrice + lineShippingCost + lineTaxCost + lineOptionCost) * lineQuantity) As orderAmount,OrderID
From vwSelectOrderLineItems group by orderid) AS C on c.orderID = a.orderID
INNER JOIN (Select SUM(payAmount) as Payment,orderID FROM vwSelectOrderPayments WHERE isnull(SUM(PayAmount),0) > 0 GROUP BY OrderID) AS d ON d.orderID = a.orderID
Left Outer Join vwSelectOrderPayments b On b.orderID = a.orderID
Where b.payValid = 1 AND a.orderPaid = 0 AND
This is a better query as you do not have to us a correlated subquery. Correlated queries are when a subquery references an outerquery row. This isn't optimal because every row the outerquery runs the correlated subquery will execute. Once you give us table definitions we can probably fix the overall data return of your query.