Related
I have a table that consists of time information. It's basically:
Employee, Date, Seq, Time In, Time Out.
They can clock out multiple times a day, so I'm trying to get all of the clock outs in a day on one row. My result would be something like:
Employee, Date, TimeIn1, TimeOut1, TimeIn2, TimeOut2, TimeIn3, TimeOut3....
Where the 1, 2, and 3 are the sequence numbers. I know I could just do a bunch of left joins to the table itself based on employee=employee, date=date, and seq=seq+1, but is there a way to do it in a pivot? I don't want to pivot the employee and date fields, just the time in and time out.
The short answer is: Yes, it's possible.
The exact code will be updated if/when you provide sample data to clarify some points, but you can absolutely pivot the times out while leaving the employee/work date alone.
Sorry for the wall of code; none of the fiddle sites are working from my current computer
declare #test table (
pk int,
workdate date,
seq int,
tIN time,
tOUT time
)
insert into #test values
(1, '2020-11-25', 1, '08:00', null),
(1, '2020-11-25', 2, null, '11:00'),
(1, '2020-11-25', 3, '11:32', null),
(1, '2020-11-25', 4, null, '17:00'),
(2, '2020-11-25', 5, '08:00', null),
(2, '2020-11-25', 6, null, '09:00'),
(2, '2020-11-25', 7, '09:15', null),
-- new date
(1, '2020-11-27', 8, '08:00', null),
(1, '2020-11-27', 9, null, '08:22'),
(1, '2020-11-27', 10, '09:14', null),
(1, '2020-11-27', 11, null, '12:08'),
(1, '2020-11-27', 12, '01:08', null),
(1, '2020-11-27', 13, null, '14:40'),
(1, '2020-11-27', 14, '14:55', null),
(1, '2020-11-27', 15, null, '17:00')
select *
from (
/* this just sets the column header names and condenses their values */
select
pk,
workdate,
colName = case when tin is not null then 'TimeIn' + cast(empDaySEQ as varchar) else 'TimeOut' + cast(empDaySEQ as varchar) end,
colValue = coalesce(tin, tout)
from (
/* main query */
select
pk,
workdate,
/* grab what pair # this clock in or out is; reset by employee & date */
empDaySEQ = (row_number() over (partition by pk, workdate order by seq) / 2) + (row_number() over (partition by pk, workdate order by seq) % 2),
tin,
tout
from #test
) i
) a
PIVOT (
max(colValue)
for colName
IN ( /* replace w/ dynamic if you don't know upper boundary of max in/out pairs */
[TimeIn1],
[TimeOut1],
[TimeIn2],
[TimeOut2],
[TimeIn3],
[TimeOut3],
[TimeIn4],
[TimeOut4]
)
) mypivotTable
generates these results.
(I would provide a fiddle demo but they're not working for me today)
First time posting!
Have a use case where we want to join some sales data to a master agreement table to determine applicable fee's at a transactional level.
The hard part is that the agreement table has VARIOUS possibilities, and in a worse case scenario at least a "catch all".
We would want to start at the *most granular" level. So the purple line matches on all possible values.
However, a field like the blue sales record does not match on any value to the master except supplier, so in that case it is a catch all.
I've thought of concat'ing all the rows in the master, but then I'd need to find a way of joining it to sales? a simple concat would not successfully join the blue row example together. So it's like the join would have to dynamically choose which columns to compare.
By chance would any users have some idea's on how to achieve this?
Thanks!
(Code for tables)
create TABLE T_TEST_AGREEMENT (
SUPPLIER VARCHAR(254),
ITEM VARCHAR(254),
PROGRAM INT,
RXDA VARCHAR(254),
CTRCT INT,
FEE INT
);
create TABLE T_TEST_AGREEMENT_SALES (
SUPPLIER VARCHAR(254),
ITEM VARCHAR(254),
PROGRAM INT,
RXDA VARCHAR(254),
CTRCT INT
);
INSERT INTO T_TEST_AGREEMENT values
(123, 'A', 60, 'Y', 4, 1),
(123, 'A', 61, 'N', 4, 2),
(123, 'B', 62, null, 5, 3),
(123, 'C', null, 'Y', 6, 4),
(123, null, 63, null, null, 5),
(123, null, null, 'Y', null, 6),
(123, null, null, null, null, 7);
INSERT INTO T_TEST_AGREEMENT_SALES values
(123, 'D', 63, null, null),
(123, 'F', null, null, null),
(123, 'A', 61, 'N', 4),
(123, 'C', null, 'Y', 6);
You can use a correlated subquery:
select st.*,
(select m.fee
from master m
where m.supplier = st.supplier and
(m.item is null or m.item = st.item) and
(m.program is null or m.program = st.program) and
(m.rxda is null or m.rxda = st.rxda) and
(m.ctrct is null or m.ctrct = st.ctrct)
order by ( (case when m.item = st.item then 1 else 0 end) +
(case when m.program = st.program then 1 else 0 end) +
(case when m.rxda = st.rxda then 1 else 0 end) +
(case when m.ctrct = st.ctrct then 1 else 0 end) +
) desc
fetch first 1 row only
) as fee
from sales_transactions st;
This uses standard SQL syntax. It might vary depending on your row.
I want to find the values of time taken by a given depot for the stationary.
Below is the code for the create table and values. I have also achieved the other requirements for the same table and also have shared the code below.
I want to create an new column [StationaryFirstWaitTime] where I can get the First wait time for the same scenario based.
For a given ShipmentId, VehicleId,
on where DepotId = StationayId get the [StationaryEndTime] - [StationaryStarttime] for the first value which is received on an given date for an specific vehicle and shipmentid.
below is the code
CREATE TABLE [dbo].[Table_Consolidate_Friday](
[Sno] [int] NOT NULL,
[VehicleId] [nchar](10) NULL,
[DepotId] [int] NULL,
[DepotVisitStartTime] [datetime2](7) NULL,
[DepotVisitEndTime] [datetime2](7) NULL,
[StationaryId] [int] NULL,
[StationaryStartTime] [datetime2](7) NULL,
[StationaryEndTime] [datetime2](7) NULL,
[ActualQty] [bigint] NULL,
[AggreageQty] [bigint] NULL,
[StationaryWaitTimeTotal] [datetime2](7) NULL,
[StationaryFirstWaitTime] [datetime2](7) NULL,
[StationaryRowCount] [bigint] NULL
) ON [PRIMARY]
GO
INSERT [dbo].[Table_Consolidate_Friday] ([Sno], [VehicleId], [DepotId], [DepotVisitStartTime], [DepotVisitEndTime], [StationaryId], [StationaryStartTime], [StationaryEndTime], [ActualQty], [AggreageQty], [StationaryWaitTimeTotal], [StationaryRowCount]) VALUES
(1, N'TN1 ', 15, '2019-02-15T07:25:33', '2019-02-15T17:25:33', 15, '2019-02-15T07:55:32', '2019-02-15T08:15:23', 10, 119, '2019-02-22T02:02:47', 4),
(1, N'TN1 ', 3, '2019-02-15T07:25:33', '2019-02-15T17:25:33', 3, '2019-02-15T09:22:52', '2019-02-15T09:45:59', 20, 119, '2019-02-22T02:02:47', 4),
(1, N'TN1 ', 8, '2019-02-15T07:25:33', '2019-02-15T17:25:33', 8, '2019-02-15T11:25:36', '2019-02-15T02:35:37', 33, 119, '2019-02-22T02:02:47', 4),
(1, N'TN1 ', 12, '2019-02-15T07:25:33', '2019-02-15T17:25:33', 12, '2019-02-15T15:15:33', '2019-02-15T15:25:21', 56, 119, '2019-02-22T02:02:47', 4),
(2, N'KA2 ', 23, '2019-02-15T06:12:52', '2019-02-15T11:21:35', 23, '2019-02-15T10:25:13', '2019-02-15T11:15:23', 72, 114, '2019-02-22T01:24:10', 2),
(2, N'KA2 ', 20, '2019-02-15T06:12:52', '2019-02-15T11:21:35', 20, '2019-02-15T07:11:33', '2019-02-15T07:45:33', 42, 114, '2019-02-22T01:24:10', 2),
(3, N'AP3 ', 20, '2019-02-15T06:32:52', '2019-02-15T11:21:35', 20, '2019-02-15T07:13:13', '2019-02-15T08:05:01', 15, 37, '2019-02-22T01:14:18', 2),
(3, N'AP3 ', 21, '2019-02-15T06:32:52', '2019-02-15T11:21:35', 21, '2019-02-15T09:43:12', '2019-02-15T10:05:42', 22, 37, '2019-02-22T01:14:18', 2),
(3, N'AP3 ', 15, '2019-02-15T13:12:21', '2019-02-15T19:23:32', 15, '2019-02-15T14:13:13', '2019-02-15T14:45:21', 34, 34, '2019-02-22T00:32:08', 1)
I have written code to add and aggregate values and count as below
SELECT
AggreageQty = SUM(ActualQty) OVER (PARTITION BY Sno, DepotVisitStartTime),
StationaryWaitTimeTotal = CAST(DATEADD(SECOND, SUM(DATEDIFF(SECOND, StationaryStartTime, StationaryEndTime) ) OVER (PARTITION BY Sno, DepotVisitStartTime), 0) AS TIME),
StationaryRowCount = COUNT(*) OVER (PARTITION BY Sno, DepotVisitStartTime)
FROM [dbo].[Table_Consolidate]
I need to get the result as below for [StationaryFirstWaitTime] as below
FirstWaitTime
0:-19:-51
0:-19:-51
0:-19:-51
0:-19:-51
0:-50:-10
0:-50:-10
0:-51:-48
0:-51:-48
0:-32:-8
Platform: Azure SQL Datawarehouse
Window aggregate function: FIRST_VALUE.
Requested extra column is indeed has a non-standard look, so FORMAT() to meet such requirement:
SQL:
SELECT
AggreageQty = SUM(ActualQty) OVER (PARTITION BY Sno, DepotVisitStartTime),
StationaryWaitTimeTotal = CAST(DATEADD(SECOND, SUM(DATEDIFF(SECOND, StationaryStartTime, StationaryEndTime) ) OVER (PARTITION BY Sno, DepotVisitStartTime), 0) AS TIME),
StationaryRowCount = COUNT(*) OVER (PARTITION BY Sno, DepotVisitStartTime),
StationaryFirstWaitTime = FORMAT(FIRST_VALUE ( CAST(DATEADD(SECOND, DATEDIFF(SECOND, StationaryStartTime, StationaryEndTime) , 0) AS datetime) ) OVER (PARTITION BY Sno, DepotVisitStartTime order by StationaryStartTime), 'H:-m:-s')
FROM [dbo].[Table_Consolidate_Friday]
That extra column of interest results to:
StationaryFirstWaitTime
0:-19:-51
0:-19:-51
0:-19:-51
0:-19:-51
0:-34:-0
0:-34:-0
0:-51:-48
0:-51:-48
0:-32:-8
Update:
OP uses SQL Datawarehouse. FORMAT() is not available there, workaround:
StationaryFirstWaitTime = REPLACE(CONVERT(VARCHAR(8),FIRST_VALUE ( CAST(DATEADD(SECOND, DATEDIFF(SECOND, StationaryStartTime, StationaryEndTime) , 0) AS TIME) ) OVER (PARTITION BY Sno, DepotVisitStartTime order by StationaryStartTime), 8), ':', ':-')
Which results to:
StationaryFirstWaitTime
00:-19:-51
00:-19:-51
00:-19:-51
00:-19:-51
00:-34:-00
00:-34:-00
00:-51:-48
00:-51:-48
00:-32:-08
I have a view that has suddenly gotten too slow and I'm at a loss of how to optimize it. The tables currently contain 15000 (#dispatchPallet) and 135000 (#pickLog) rows respectively.
I've written a minimized piece of code to show the important parts below.
DECLARE #dispatchPallet TABLE
(
[PICK_PALL_NUM] [bigint] NOT NULL,
[PALLET_PLACEMENT] [nvarchar](4) NOT NULL,
[SHIPMENT_ID] [nvarchar](255) NULL
)
DECLARE #pickLog TABLE
(
[LINE_NUM] [int] NOT NULL,
[QTY_PRE] [numeric](9, 2) NULL,
[QTY_SUF] [numeric](9, 2) NULL,
[PICK_PALL_NUM] [bigint] NULL,
[ROWID] [uniqueidentifier] NOT NULL,
[WEIGHT_GROSS] [numeric](9, 3) NULL,
[VOLUME] [numeric](9, 3) NULL
)
INSERT INTO #dispatchPallet ([PICK_PALL_NUM], [PALLET_PLACEMENT], [SHIPMENT_ID])
VALUES
(4797753, 'B', 'SHIPMENT-1'),
(4797752, 'B', 'SHIPMENT-2'),
(4797750, 'B', 'SHIPMENT-3'),
(4797749, 'B', 'SHIPMENT-4'),
(4797739, 'B', 'SHIPMENT-5'),
(4797732, 'B', 'SHIPMENT-6'),
(4797731, 'B', 'SHIPMENT-7'),
(4797730, 'B', 'SHIPMENT-7'),
(4797723, 'B', 'SHIPMENT-8'),
(4797713, 'B', 'SHIPMENT-9')
INSERT INTO #pickLog ([LINE_NUM], [QTY_PRE], [QTY_SUF], [PICK_PALL_NUM], [ROWID], [WEIGHT_GROSS])
VALUES
(30, 54, 54, 4797753, NEWID(), 1070.280),
(10, 24, 24, 4797752, NEWID(), 471.360),
(30, 12, 12, 4797750, NEWID(), 237.960),
(320, 25, 25, 4797749, NEWID(), 102.750),
(110, 3, 3, 4797739, NEWID(), 40.650),
(40, 12, 12, 4797732, NEWID(), 238.080),
(50, 4, 4, 4797732, NEWID(), 78.560),
(20, 20, 20, 4797731, NEWID(), 110.000),
(20, 40, 40, 4797730, NEWID(), 220.000),
(1340, 3, 3, 4797723, NEWID(), 14.250),
(410, 2, 2, 4797723, NEWID(), 4.780),
(440, 2, 2, 4797723, NEWID(), 21.000),
(480, 1, 1, 4797723, NEWID(), 3.500),
(1290, 2, 2, 4797723, NEWID(), 39.280),
(470, 1, 1, 4797723, NEWID(), 8.500),
(280, 3, 3, 4797723, NEWID(), 16.500),
(10, 2, 2, 4797723, NEWID(), 10.700),
(500, 2, 2, 4797723, NEWID(), 6.600),
(290, 1, 1, 4797713, NEWID(), 0.540),
(40, 2, 2, 4797713, NEWID(), 33.800)
SELECT
[dispatchPallet].[SHIPMENT_ID],
SUM([pickLog].[QTY_SUF]) AS KOLLI,
COUNT(DISTINCT [pickLog].[LINE_NUM]) AS LINES,
SUM([pickLog].[WEIGHT_GROSS]) AS PICKED_WEIGHT,
COUNT(DISTINCT [pickLog].[PICK_PALL_NUM]) AS PALLETS,
COUNT(DISTINCT CASE WHEN [dispatchPallet].[PALLET_PLACEMENT] = 'B' THEN [dispatchPallet].[PICK_PALL_NUM] ELSE NULL END) AS BOTTOM_PALLETS
FROM
#dispatchPallet dispatchPallet
INNER JOIN #pickLog pickLog ON [dispatchPallet].[PICK_PALL_NUM] = [pickLog].[PICK_PALL_NUM]
GROUP BY
[dispatchPallet].[SHIPMENT_ID]
-- Expected output:
-- SHIPMENT_ID KOLLI LINES PICKED_WEIGHT PALLETS BOTTOM_PALLETS
-- SHIPMENT-1 54.00 1 1070.280 1 1
-- SHIPMENT-2 24.00 1 471.360 1 1
-- SHIPMENT-3 12.00 1 237.960 1 1
-- SHIPMENT-4 25.00 1 102.750 1 1
-- SHIPMENT-5 3.00 1 40.650 1 1
-- SHIPMENT-6 16.00 2 316.640 1 1
-- SHIPMENT-7 60.00 1 330.000 2 2
-- SHIPMENT-8 18.00 9 125.110 1 1
-- SHIPMENT-9 3.00 2 34.340 1 1
You should at least create primary constraint on as
ALTER TABLE #dispatchPallet TABLE ADD PRIMARY KEY (PICK_PALL_NUM);
Foreign Key constraint as
ALTER TABLE #pickLog TABLE ADD foreign key (PICK_PALL_NUM) references #dispatchPallet(PICK_PALL_NUM)
Also create a unique index on
CREATE UNIQUE NONCLUSTERED INDEX idx_PALLET_PLACEMENT_notnull
ON #dispatchPallet(PALLET_PLACEMENT)
WHERE PALLET_PLACEMENT IS NOT NULL;
Your query is simple and there isn't much room to optimize. You should check that you at least have indexes on dispatchPallet by SHIPMENT_ID and on pickLog by PICK_PALL_NUM. These would be the best choices for your query:
CREATE NONCLUSTERED INDEX NCI_dispatchPallet_shipment_ID
ON dispatchPallet (SHIPMENT_ID, PICK_PALL_NUM)
INCLUDE (PALLET_PLACEMENT)
CREATE NONCLUSTERED INDEX NCI_pickLog_pick_pall_num
ON pickLog (PICK_PALL_NUM)
INCLUDE (QTY_SUF, LINE_NUM, WEIGHT_GROSS)
You should also validate if you need your COUNT to be DISTINCT or not (distinct is an expensive operation).
Last but not least, you should really check how you access the view; if you are filtering it, joining it, etc. These other conditions might generate different query plans and make your performance go down if not managed correctly (even with the right indexes!).
For starters there should be primary keys and foreign keys on these tables so that this query can do index seeks/scans (paparazzo's comment above) as opposed to full table seeks/scans.
In addition to the bigint/int, what's the purpose of the uniqueidentifier?
I have a simple view created in VS 2017. Here it is:
CREATE VIEW [dbo].[ApplicantStat]
AS SELECT ISNULL(CONVERT(VARCHAR(50), NEWID()), '') AS ID,
ISNULL(AVG(ApplicationTime), 0) AS 'AvgApplicationTime',
ISNULL(AVG(ResponseTime), 0) AS 'AvgResponseTime',
ISNULL(CAST(COUNT(CASE WHEN [IsAccepted] = 1 THEN 1 END) / COUNT(CASE WHEN [IsValid] = 1 THEN 1 END) AS float), 0) AS 'PctAccepted'
FROM [Application]
WHERE CreatedOn BETWEEN CAST(GETDATE()-30 AS date) AND CAST(GETDATE()-1 AS date)
As you can see, it gets data between 2 dates and does some simple aggregation.
The idea of the cast is that I want to ignore the time and get everything for the date range regardless - so as of today, 15th Mar, I would it to fetch everything for 14th March 00:00:00 - 23:59:59 and 29 days previous.
This does not happen - it picks up 3 rows (13th) - it should pick up all 5 rows. And yes, my system date is currently 15/03/2018 14:44 (UK time).
Here's, the table and data:
CREATE TABLE [dbo].[Application] (
[Id] INT NOT NULL,
[ApplicantId] INT NOT NULL,
[LoanAmount] INT NOT NULL,
[LoanTerm] SMALLINT NOT NULL,
[EmailAddress] VARCHAR (254) NOT NULL,
[MobilePhone] VARCHAR (11) NOT NULL,
[House] VARCHAR (25) NOT NULL,
[Street] VARCHAR (50) NOT NULL,
[TownCity] VARCHAR (50) NOT NULL,
[Postcode] VARCHAR (7) NOT NULL,
[IpAddress] VARCHAR (39) NOT NULL,
[IsValid] BIT NOT NULL,
[IsAccepted] BIT NOT NULL,
[Commission] DECIMAL (9, 2) NOT NULL,
[Processors] VARCHAR (500) NOT NULL,
[ResponseTime] SMALLINT NOT NULL,
[ApplicationTime] SMALLINT NOT NULL,
[CreatedOn] DATETIME NOT NULL,
PRIMARY KEY CLUSTERED ([Id] ASC)
);
INSERT INTO [dbo].[Application] ([Id], [ApplicantId], [LoanAmount], [LoanTerm], [EmailAddress], [MobilePhone], [House], [Street], [TownCity], [Postcode], [IpAddress], [IsValid], [IsAccepted], [Commission], [Processors], [ResponseTime], [ApplicationTime], [CreatedOn]) VALUES (1, 1, 300, 3, N'john.doe#tmail.com', N'07957000000', N'1', N'Acacia Avenue', N'Suburbia', N'SB1 2RB', N'100.100.100.100', 1, 1, CAST(3.20 AS Decimal(9, 2)), N'1,2,3,4,5', 90, 600, N'2018-03-13 08:00:00')
INSERT INTO [dbo].[Application] ([Id], [ApplicantId], [LoanAmount], [LoanTerm], [EmailAddress], [MobilePhone], [House], [Street], [TownCity], [Postcode], [IpAddress], [IsValid], [IsAccepted], [Commission], [Processors], [ResponseTime], [ApplicationTime], [CreatedOn]) VALUES (2, 2, 500, 12, N'a#b.com', N'0', N'1', N'a', N's', N's', N'1', 0, 1, CAST(5.00 AS Decimal(9, 2)), N'1', 60, 300, N'2018-03-14 16:00:00')
INSERT INTO [dbo].[Application] ([Id], [ApplicantId], [LoanAmount], [LoanTerm], [EmailAddress], [MobilePhone], [House], [Street], [TownCity], [Postcode], [IpAddress], [IsValid], [IsAccepted], [Commission], [Processors], [ResponseTime], [ApplicationTime], [CreatedOn]) VALUES (3, 3, 1000, 6, N'a#b.com', N'0', N'1', N'a', N's', N's', N'1', 1, 1, CAST(7.00 AS Decimal(9, 2)), N'1', 75, 360, N'2018-03-13 10:00:00')
INSERT INTO [dbo].[Application] ([Id], [ApplicantId], [LoanAmount], [LoanTerm], [EmailAddress], [MobilePhone], [House], [Street], [TownCity], [Postcode], [IpAddress], [IsValid], [IsAccepted], [Commission], [Processors], [ResponseTime], [ApplicationTime], [CreatedOn]) VALUES (4, 4, 2000, 24, N'a#b.com', N'0', N'1', N'a', N's', N's', N'1', 1, 1, CAST(20.00 AS Decimal(9, 2)), N'1', 30, 365, N'2018-03-14 11:00:00')
INSERT INTO [dbo].[Application] ([Id], [ApplicantId], [LoanAmount], [LoanTerm], [EmailAddress], [MobilePhone], [House], [Street], [TownCity], [Postcode], [IpAddress], [IsValid], [IsAccepted], [Commission], [Processors], [ResponseTime], [ApplicationTime], [CreatedOn]) VALUES (5, 5, 3000, 18, N'a#b.com', N'0', N'1', N'a', N's', N's', N'1', 1, 1, CAST(40.00 AS Decimal(9, 2)), N'1', 45, 330, N'2018-03-13 12:00:00')
Try this out:
WHERE
CreatedOn >= CAST(GETDATE()-30 AS date) AND
CreatedOn < CAST(GETDATE() AS date)
The problem is your converting to date the day before today.
You can CAST your CreatedOn field as DATE to remove the time portion, which is getting in your way here...
Perhaps
WHERE CAST(CreatedOn AS DATE) BETWEEN CAST(GETDATE()-30 AS date) AND CAST(GETDATE()-1 AS date)
BUT - CASTing a field in the WHERE expression may make it non SARGable. See here. So avoid this solution for large or production environments unless you know the expression will be SARGable. Use only as a test to refine your logic and options. (Even if there is no explicit index on CreatedOn - it may still suffer as SQL builds its own indexes all the time if no index exists explicitly.
Always worth confirming whether it is SARGable so you know for sure.)
To see what is happening - view your values in your SELECT - just to get an idea of what is working
For example:
SELECT TOP 1000
CreatedOn
,CAST(GETDATE()-30 AS date)
,CAST(GETDATE()-1 AS date)
FROM [Application]
Or see the other options for removing time values from datatime fields here
as you may want to coerce or round the time value instead
Instead of trying to ignore the time value, just make sure that your search terms are accurate for it. Also, don't blindly add things like ISNULL to every column. Spend a few seconds thinking if it's relevant or not. NEWID() for example, is never going to return a NULL value to you. Adding that kind of code is poor programming which will lead to less legible code.
Here's how I would write it to account for the time portions:
CREATE VIEW dbo.ApplicantStat
AS
SELECT
CONVERT(VARCHAR(50), NEWID()) AS ID,
COALESCE(AVG(ApplicationTime), 0) AS AvgApplicationTime,
COALESCE(AVG(ResponseTime), 0) AS AvgResponseTime,
COALESCE(CAST(COUNT(CASE WHEN [IsAccepted] = 1 THEN 1 END) / COUNT(CASE WHEN [IsValid] = 1 THEN 1 END) AS float), 0) AS PctAccepted
FROM
dbo.Application
WHERE
CreatedOn >= DATEADD(DAY, -30, CAST(GETDATE() AS DATE)) AND
CreatedOn < CAST(GETDATE() AS DATE)