I have this query that works but it is slow
SELECT
ID_NODE,
-- this case slows down the query!!!
CASE WHEN (EXISTS (SELECT MV.ID_CHILD FROM MYVIEW MV INNER JOIN MYTABLE1 MT1 ON MT1.ID_NODE = MV.ID_CHILD WHERE MV.ID_PARENT = CA.ID_NODE AND ID_FATHER IS NOT NULL)) THEN 'Y' ELSE 'N' END AS HAVE_CHILDREN,
OTHER_FIELDS
FROM
MYTABLE2
Update: After the first answer I realized my sample was not perfect, so i modified it doign 2 changes (CA to MT1, and writing MT1.ID_FATHER isntead of ID_FATHER)
SELECT
ID_NODE,
-- this case slows down the query!!!
CASE WHEN (EXISTS (SELECT MV.ID_CHILD FROM MYVIEW MV INNER JOIN MYTABLE1 MT1 ON MT1.ID_NODE = MV.ID_CHILD WHERE MV.ID_PARENT = MT2.ID_NODE AND MT1.ID_FATHER IS NOT NULL)) THEN 'Y' ELSE 'N' END AS HAVE_CHILDREN,
OTHER_FIELDS
FROM
MYTABLE2
End of update
Basically I want a 'y'/'n' result about "does this node have a child?
In execution plan i see only one warning that is:
Nested Loop (inner Join)) 43%
Could you please suggest an improvement to the query?
As exterme solution i can store in the table the HAVE_CHILDREN value as a new field, but i don't like this because it is an "highway to bugs".
Note for Bounty:
I post here the original tables, view (made with CREATE statements) and query to help provide a reply:
--This is MYTABLE1
CREATE TABLE [dbo].[MAN_PRG_OPERAZIONI](
[ID_PROG_OPERAZIONE] [int] NOT NULL,
[ID_CESPITE] [int] NOT NULL,
[ID_TIPO_OPERAZIONE] [int] NOT NULL,
[SEQUENZA] [int] NOT NULL,
[ID_RESPONSABILE] [int] NULL,
[DATA_SCADENZA] [datetime] NULL,
[DATA_ULTIMA] [datetime] NULL,
[ID_TIPO_FREQUENZA] [int] NOT NULL,
[FREQUENZA] [int] NOT NULL,
[NOTIFICA_SCADENZA] [nchar](1) NOT NULL,
[COSTO_FISSO] [numeric](19, 4) NOT NULL,
[NOTE] [nvarchar](max) NULL,
[ID_CONTO_FORNITORE] [int] NULL,
[ID_ESECUTORE] [int] NULL,
[GIORNI_INTERVENTO_PREVISTI] [int] NOT NULL,
[RIPETIZIONE] [nchar](1) NOT NULL,
[RIPETIZIONE_CONTINUA] [nchar](1) NOT NULL,
[RIPETI_FINO_A] [datetime] NULL,
[SOSPESO] [nchar](1) NOT NULL,
[ORE_LAVORO_PREVISTE] [decimal](8, 2) NOT NULL,
[DESCR_TITOLO_OPERAZIONE] [nvarchar](100) NOT NULL,
[ID_TEMPLATE] [int] NULL,
[TEMPLATE] [nvarchar](25) NULL,
[ID_PARENT_TEMPLATE_REMOTE] [int] NULL,
[ATTIVO] [nchar](1) NOT NULL,
[ID_PARENT_TEMPLATE] [int] NULL,
[NOTIFY_RESPONSIBLE] [nchar](1) NULL,
[NOTIFY_EXECUTOR] [nchar](1) NULL,
[NOTIFY_OTHERS] [nvarchar](200) NULL,
[NOTIFY_INADVANCE] [nchar](1) NULL,
[NOTIFY_ADVANCE_DAYS] [int] NULL,
[NOTIFY_ONEXECUTION] [nchar](1) NULL,
[NOTIFY_ONCLOSE] [nchar](1) NULL,
[ID_UTENTE_INS] [int] NULL,
[DATA_INS] [datetime] NULL,
[ID_UTENTE_ULT_MOD] [int] NULL,
[DATA_ULTIMA_MOD] [datetime] NULL,
[STATO_CKL] [int] NOT NULL,
[TAGAPPSYNC] [nchar](1) NOT NULL,
[IS_FATHER] [nchar](1) NOT NULL,
[ID_FATHER] [int] NULL,
[NOTIFY_DELAYS] [nchar](1) NULL,
[NOTIFY_DELAYS_DAYS] [int] NULL,
[NOTIFY_INS_USER] [nchar](1) NULL,
CONSTRAINT [PK_MAN_PRG_OPERAZIONI] PRIMARY KEY CLUSTERED
(
[ID_PROG_OPERAZIONE] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [PRIMARY]
) ON [PRIMARY]
--This is MYTABLE2
CREATE TABLE [dbo].[CES_ANAGRAFICA](
[ID_CESPITE] [int] NOT NULL,
[ID_CESPITE_PADRE] [int] NULL,
[COD_CESPITE] [nvarchar](50) NOT NULL,
[DESCR_CESPITE] [nvarchar](120) NOT NULL,
[IMMATERIALE] [nchar](1) NOT NULL,
[DATA_ACQUISTO] [datetime] NULL,
[DATA_ENTRATA_FUNZIONE] [datetime] NULL,
[DATA_DISMISSIONE] [datetime] NULL,
[BENE_USATO] [nchar](1) NOT NULL,
[ID_UBICAZIONE] [int] NULL,
[NRO_IDENTIFICAZIONE] [nvarchar](50) NULL,
[MARCA] [nvarchar](50) NULL,
[MODELLO] [nvarchar](50) NULL,
[MARCATURA_CE] [nchar](1) NULL,
[ANNO_COSTRUZIONE] [int] NULL,
[MATRICOLA_COSTRUTTORE] [nvarchar](50) NULL,
[COSTRUTTORE] [nvarchar](80) NULL,
[ID_CONTO_FORNITORE] [int] NULL,
[NOTE] [nvarchar](max) NULL,
[ID_TIPO_CESPITE] [int] NOT NULL,
[ID_STATO_CESPITE] [int] NULL,
[ID_CONTO_PROPRIETA] [int] NULL,
[ID_RESPONSABILE] [int] NULL,
[DATA_SCAD_GARANZIA] [datetime] NULL,
[CAMPO_MISURA] [nvarchar](80) NULL,
[CRITERI_ACC] [nvarchar](80) NULL,
[RISOLUZIONE] [nvarchar](80) NULL,
[ID_USO_STRUMENTO] [int] NULL,
[ID_REFERENTE] [int] NULL,
[FOTO] [varbinary](max) NULL,
[PROF_ID] [int] NOT NULL,
[ID_TEMPLATE] [int] NULL,
[TEMPLATE] [nvarchar](25) NULL,
[ID_PARENT_TEMPLATE_REMOTE] [int] NULL,
[ID_PARENT_TEMPLATE] [int] NULL,
[ISLOCKED] [nchar](1) NULL,
[TAGAPPSYNC] [nchar](1) NOT NULL,
[TAGAPPDOCSYNC] [nchar](1) NOT NULL,
CONSTRAINT [PK_CES_ANAGRAFICA] PRIMARY KEY CLUSTERED
(
[ID_CESPITE] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [PRIMARY]
) ON [PRIMARY]
--This is MYVIEW
CREATE VIEW [dbo].[V_CESPITE_TREE] AS
--BEGIN
WITH q AS
(
SELECT ID_CESPITE , ID_CESPITE AS ID_CESPITE_ANCESTOR
FROM CES_ANAGRAFICA c
JOIN CES_TIPI_CESPITE ctc ON ctc.ID_TIPI_INFRSTR = c.ID_TIPO_CESPITE
UNION ALL
SELECT c.ID_CESPITE, q.ID_CESPITE_ANCESTOR
FROM q
JOIN CES_ANAGRAFICA c
ON c.ID_CESPITE_PADRE = q.ID_CESPITE
JOIN CES_TIPI_CESPITE ctc ON ctc.ID_TIPI_INFRSTR = c.ID_TIPO_CESPITE
)
select ID_CESPITE AS ID_CHILD, ID_CESPITE_ANCESTOR AS ID_PARENT from q
GO
-- So my original query was this:
SELECT
CA.ID_CESPITE,CASE WHEN (EXISTS (SELECT VCA.ID_CHILD FROM V_CESPITE_TREE VCA INNER JOIN MAN_PRG_OPERAZIONI MPO ON MPO.ID_CESPITE = VCA.ID_CHILD WHERE VCA.ID_PARENT = CA.ID_CESPITE AND ID_FATHER IS NOT NULL)) THEN 'Y' ELSE 'N' END AS HAVE_CHILD_PRG,
CA.ID_CESPITE_PADRE
<Other Fields>
FROM
CES_ANAGRAFICA CA LEFT OUTER JOIN
CES_PERMESSI CP ON ((CA.ID_CESPITE = CP.ID_CESPITE)) INNER JOIN CES_TIPI_CESPITE CTCS ON CA.ID_TIPO_CESPITE = CTCS.ID_TIPI_INFRSTR LEFT OUTER JOIN
V_UTENTI_DIPENDENTI VUD ON CA.ID_RESPONSABILE = VUD.ID_DIPENDENTE
SELECT
CA.ID_CESPITE,
CASE WHEN child.[Count] > 0 THEN 'Y' ELSE 'N' END AS HAVE_CHILD_PRG,
CA.ID_CESPITE_PADRE
FROM
CES_ANAGRAFICA CA
LEFT OUTER JOIN CES_PERMESSI CP
ON ((CA.ID_CESPITE = CP.ID_CESPITE))
INNER JOIN CES_TIPI_CESPITE CTCS
ON CA.ID_TIPO_CESPITE = CTCS.ID_TIPI_INFRSTR
LEFT OUTER JOIN V_UTENTI_DIPENDENTI VUD
ON CA.ID_RESPONSABILE = VUD.ID_DIPENDENTE
CROSS APPLY (
SELECT [Count] = COUNT(*)
FROM V_CESPITE_TREE VCA
JOIN MAN_PRG_OPERAZIONI MPO
ON MPO.ID_CESPITE = VCA.ID_CHILD
WHERE VCA.ID_PARENT = CA.ID_CESPITE
AND MPO.ID_FATHER is not null
) child
This should perform slightly better since it doesn't have to perform an aggregate function.
SELECT
CA.ID_CESPITE,
CASE WHEN child.[Exists] = 1 THEN 'Y' ELSE 'N' END AS HAVE_CHILD_PRG,
CA.ID_CESPITE_PADRE
FROM
CES_ANAGRAFICA CA
LEFT OUTER JOIN CES_PERMESSI CP
ON ((CA.ID_CESPITE = CP.ID_CESPITE))
INNER JOIN CES_TIPI_CESPITE CTCS
ON CA.ID_TIPO_CESPITE = CTCS.ID_TIPI_INFRSTR
LEFT OUTER JOIN V_UTENTI_DIPENDENTI VUD
ON CA.ID_RESPONSABILE = VUD.ID_DIPENDENTE
OUTER APPLY (
SELECT TOP (1) 1 [Exists]
FROM V_CESPITE_TREE VCA
JOIN MAN_PRG_OPERAZIONI MPO
ON MPO.ID_CESPITE = VCA.ID_CHILD
WHERE VCA.ID_PARENT = CA.ID_CESPITE
AND MPO.ID_FATHER is not null
) child
Use a CTE ; it will load your inner join once and then cache it.
Note I don't know where the CA.ID_NODE comes from as you didn't explain that.
Also your inner query joins to MyTable1, but you're not relating MyTable2 and the subquery.
Given off what you've provided, the pseudo-code should be something like this:
(If you update your question with pertinent info I'll update this answer to reflect it).
Update:
Here's an updated version based on your schema update and some sample data. I confirmed this no longer causes duplicates. The real question is for you to check it and make sure it increases the performance, aka lowers execution time.
; with hasChildCte(ID_CESPITE, ID_PARENT)
As (
SELECT VCA.ID_CHILD,
vca.ID_PARENT
FROM V_CESPITE_TREE VCA
INNER JOIN MAN_PRG_OPERAZIONI MPO
ON MPO.ID_CESPITE = VCA.ID_CHILD
WHERE ID_FATHER
IS NOT NULL
)
Select
CA.ID_CESPITE,
Case
When Exists (
Select ID_PARENT
From hasChildCte cte
Where cte.ID_PARENT = ca.ID_CESPITE
) Then 'Y'
Else 'N'
End As HAVE_CHILDREN,
CA.ID_CESPITE_PADRE
From CES_ANAGRAFICA CA
Note also if you don't have indexes on all of the joined columns, it would be a good move to put those in. This will help to speed up the query further especially if you're working with a large amount of data.
Update 2
The comment about the CTE executing more than once got me thinking, and it is apparently up to SQL server to decide to cache a CTE or not, rather than always caching. In many cases CTE will execute only once, but other times it's similar to a view in SQL server and doesn't get cached.
Consequently, I've modified the code to use a table variable instead. I don't have enough test data to see which performs better or faster, though.
Try this and see if it yields a faster query execution time. Note also regardless of which method of refactoring and performance improvement you choose, it's a good idea to have your database properly setup with indexes on the columns you are using in JOIN's. This increases query execution time significantly, at the slight cost on inserts of the index having to be updated.
The updated, non-CTE, code, using a table variable instead:
Declare #HasChildren table (ID_CESPITE int, ID_PARENT int)
Insert into #HasChildren
Select VCA.ID_CHILD,
vca.ID_PARENT
From V_CESPITE_TREE VCA
Inner Join MAN_PRG_OPERAZIONI MPO
On MPO.ID_CESPITE = VCA.ID_CHILD
Where ID_FATHER
Is Not Null
Select
CA.ID_CESPITE,
Case
When Exists (
Select ID_PARENT
From #HasChildren c
Where c.ID_PARENT = ca.ID_CESPITE
) Then 'Y'
Else 'N'
End As HAVE_CHILDREN,
CA.ID_CESPITE_PADRE
From CES_ANAGRAFICA CA
Something like the below might be a little easier for the optimizer to handle.
SELECT DISTINCT
ID_NODE,
CASE WHEN MTSub.ID_CHILD is null then 'N' else 'Y' END,
OTHERFIELDS
FROM MYTABLE2
LEFT JOIN
(SELECT MV.ID_CHILD FROM MYVIEW MV INNER JOIN MYTABLE1 MT1 ON MT1.ID_NODE = MV.ID_CHILD WHERE MV.ID_PARENT = MT2.ID_NODE AND MT1.ID_FATHER IS NOT NULL) MTSub
Related
I have a stored procedure that, when ran, does an initial insert into a a table from a view, followed by an update statement that modifies a table in the view the first select statement uses (code is below):
ALTER PROCEDURE [dbo].[LFC_sp_LIT_PgmrRequestForm]
AS
BEGIN
SET NOCOUNT ON;
insert into firebird.helpdesk.dbo.tbl_program_request (Requester, Description, Priority, DateRequest, project_status, department, category, requester_email, DueDate, Note)
select dept_name, submitter_first_name + '-' + issue_description, severity_level, getdate(), 'Not Started', dept_name, issue_category, submitter_email, date_due, issue_details
from ics_net..CUS_CF_PGMR_REQUEST_View
where finalbalance = 0;
UPDATE ics_net..CF_Submission
SET finalbalance = 5
WHERE finalbalance = 0
AND FormId = '79A807D9-230B-494C-A609-A284DBBE41B8';
END
This procedure is called whenever a web form is submitted, and the goal is to move the data from the web form database into our help desk database. The web form has a final balance field in the database, that is set to zero. When it is moved, we update it to a non-zero number.
What happens is that the first statement executes, but the second update never happens. Once this is called again, the first statement executes, and the second one works for the statement that was supposed to be previously updated. Things I've tried to resolve the issue are:
Use the ROWLOCK hint for both statements
I've made sure the transaction isolation level is READ COMMITTED
I can't think of anything else to do, other than to use the NOLOCK hint on the select statement, but I'm very hesitant to do that. Any ideas? Thanks.
EDIT 1) Based on some discussion, I want to clarify a couple things:
There aren't any existing triggers on any of the tables
underlying this query.
The initial select is based on a view, while the second update
references a table that makes up the view.
Edit 2) Some more details
The view definition:
ALTER VIEW [dbo].[CUS_CF_PGMR_REQUEST_View] AS
select s.SubmissionId,
s.FormId,
s.SubmittedDate,
s.UserId,
s.Status,
sfn.AnswerValue as [submitter_first_name],
sub_email.AnswerValue as [submitter_email],
dname.AnswerValue as [dept_name],
d_due.AnswerValue as [date_due],
i_cat.AnswerValue as [issue_category],
sec_lev.AnswerValue as [severity_level],
i_desc.AnswerValue as [issue_description],
i_det.AnswerValue as [issue_details],
s.FinalBalance
from CF_Submissions s
left outer join CF_Answers sfn on sfn.ItemID = 'df5307ca-d9a8-4c74-955e-7fe80caafdc0'
and sfn.SubmissionID=s.SubmissionID
left outer join CF_Answers sub_email on sub_email.ItemID = '27e8e2fd-13f8-4c5a-a6bb-bc68fa7d4af5'
and sub_email.SubmissionID=s.SubmissionID
left outer join CF_Answers dname on dname.ItemID = '2826ee1b-759e-4325-b0ba-32a86ed7f07a'
and dname.SubmissionID=s.SubmissionID
left outer join CF_Answers d_due on d_due.ItemID = '5e087866-63ce-41f1-bb32-443770fdf388'
and d_due.SubmissionID=s.SubmissionID
left outer join CF_Answers i_cat on i_cat.ItemID = '32be52b1-1539-4d9b-9f7c-ffb370188396'
and i_cat.SubmissionID=s.SubmissionID
left outer join CF_Answers sec_lev on sec_lev.ItemID = 'f795ff66-342b-4155-86d6-7655dc2b10a5'
and sec_lev.SubmissionID=s.SubmissionID
left outer join CF_Answers i_desc on i_desc.ItemID = '3ff0e614-bdf6-4710-9ba0-6f7356c67032'
and i_desc.SubmissionID=s.SubmissionID
left outer join CF_Answers i_det on i_det.ItemID = 'dd5b797d-a407-4bc7-a73c-daacb3abe660'
and i_det.SubmissionID=s.SubmissionID
where s.FormId = '79a807d9-230b-494c-a609-a284dbbe41b8'
Table Definitions Underlying The View
CREATE TABLE [dbo].[CF_Answers](
[AnswerID] [uniqueidentifier] NOT NULL,
[SubmissionID] [uniqueidentifier] NULL,
[ItemID] [uniqueidentifier] NULL,
[AnswerValue] [varchar](max) NULL,
[MItemID] [uniqueidentifier] NULL,
[RowIndex] [int] NULL,
[ChildItemID] [uniqueidentifier] NULL,
[DisplayText] [varchar](max) NULL,
[NumericValue] [numeric](8, 2) NULL,
[IsVisibleOnSubmit] [bit] NULL,
CONSTRAINT [PK_CF_Answers] PRIMARY KEY CLUSTERED
(
[AnswerID] 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
CREATE TABLE [dbo].[CF_Submissions](
[SubmissionID] [uniqueidentifier] NOT NULL,
[UserID] [uniqueidentifier] NULL,
[FormID] [uniqueidentifier] NULL,
[SubmittedDate] [datetime] NULL,
[FinalBalance] [decimal](18, 2) NULL,
[WorkflowID] [uniqueidentifier] NULL,
[Status] [int] NULL,
[TransactionID] [varchar](50) NULL,
[WaiverCode] [varchar](max) NULL,
CONSTRAINT [PK_CF_Submissions] PRIMARY KEY CLUSTERED
(
[SubmissionID] 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
The definition of the destination table for the insert:
CREATE TABLE [dbo].[tbl_program_request](
[ID] [int] IDENTITY(1,1) NOT NULL,
[Requester] [nvarchar](50) NULL,
[Description] [nvarchar](255) NULL,
[Priority] [nvarchar](10) NULL,
[DateRequest] [datetime] NULL,
[WorkingOn] [nvarchar](30) NULL,
[CompletedDate] [datetime] NULL,
[StartDate] [nvarchar](15) NULL,
[Note] [nvarchar](max) NULL,
[project_status] [nvarchar](25) NULL,
[hours_week] [decimal](4, 2) NULL,
[hours_total] [decimal](10, 2) NULL,
[department] [nvarchar](30) NULL,
[category] [nvarchar](20) NULL,
[requester_email] [nvarchar](30) NULL,
[DueDate] [datetime] NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
Finally, some sample data that was pulled from the view:
SubmissionId - B81CE5F8-A87B-42B1-9339-2B36166394AB
FormId - 79A807D9-230B-494C-A609-A284DBBE41B8
SubmittedDate - 1/24/2018 16:43
UserId - 58E3958A-A786-4CB9-8EDE-0837ACE187BD
Status - 1
submitter_first_name - SM
submitter_email - email#organization
dept_name - LIT
date_due - 1/28/2018
issue_category -MISC
severity_level - LOW
issue_description - test3
issue_details - test3
FinalBalance - 0
Just to clarify, at the end of the SP, FinalBalance should equal 5. However, it isn't set to 5 until the second time it's ran, causing a double insert into the tbl_program_request table.
I'm trying to find all customers who have placed an order but there isn't a callback after their last order date.
My current query:
SELECT dbo.[Order].CustomerId, MAX(OrderDate) AS OrderDate, NextCallbackDate, UserName
FROM dbo.[Order]
LEFT OUTER JOIN (SELECT MAX(CallbackDate) NextCallbackDate, CustomerID
FROM AccountCallbacks
GROUP By CustomerId
) callbacks ON callbacks.CustomerID = dbo.[Order].CustomerID
LEFT OUTER JOIN dbo.aspnet_Users users ON dbo.[Order].UserID = users.UserId
WHERE (PaymentTypeID IN (2, 3, 4, 6, 8))
AND OrderDate >= NextCallbackDate
GROUP BY dbo.[Order].CustomerID, dbo.[Order].OrderDate,callbacks.NextCallbackDate, UserName
ORDER BY dbo.[Order].CustomerID
Tables:
AccountCallBacks:
[CallbackID] [int] IDENTITY(1,1) NOT NULL,
[UserID] [uniqueidentifier] NOT NULL,
[CustomerID] [int] NOT NULL,
[Created] [datetime] NOT NULL,
[CallbackDate] [date] NOT NULL,
[Enabled] [bit] NOT NULL,
[CallbackTimeID] [int] NULL,
[GaryCust] [bit] NULL,
[NotInterestedReasonID] [int] NULL
Order Table:
[OrderID] [int] IDENTITY(1,1) NOT NULL,
[CustomerID] [int] NULL,
[UserID] [uniqueidentifier] NULL,
[OrderDate] [datetime] NOT NULL,
[PaymentTypeID] [int] NULL,
[PaymentStatusID] [int] NOT NULL,
[PaymentDate] [datetime] NULL,
[TransactionRef] [varchar](50) NULL
And the aspnet_Users table is the usual .net membership users table
EDIT:
Apologies! I never actual said what was wrong! My query doesn't give me what I'm expecting one of the rows of data for a particular CustomerID isn't in the result set. And no, there should always be at least one AccountCallbacks.CallbackDate for every CustomerID as I'm joining on the dbo.[Order] table and they wouldn't be in there without first ever being in the AccountCallbacks table.
Feel free to ask any other info, help is greatly appreciated.
I have big log4net database table with this structure.
CREATE TABLE [dbo].[Log]
(
[Id] [INT] IDENTITY(1,1) NOT NULL,
[Date] [DATETIME] NOT NULL,
[Thread] [VARCHAR](255) NOT NULL,
[Level] [VARCHAR](50) NOT NULL,
[Logger] [VARCHAR](255) NOT NULL,
[Application] [VARCHAR](50) NOT NULL,
[Server] [VARCHAR](50) NOT NULL,
[Message] [VARCHAR](4000) NOT NULL,
[Exception] [TEXT] NULL,
[UserName] [NVARCHAR](50) NULL,
[CorrelationId] [VARCHAR](255) NULL,
CONSTRAINT [PK_Log] PRIMARY KEY CLUSTERED
(
[Id] ASC
)
But this table has cca 250 000 000 rows. I need return count for table. Standard way is (generated by entity framework )
SELECT [GroupBy1].[A1] AS [C1]
FROM (SELECT COUNT(1) AS [A1]
FROM [dbo].[Log] AS [Extent1]
WHERE ((([Extent1].[Level] = 'DEBUG')
AND ('DEBUG' IS NOT NULL))
OR (([Extent1].[Level] = 'INFO')
AND ('INFO' IS NOT NULL))
OR (([Extent1].[Level] = 'WARN')
AND ('WARN' IS NOT NULL)))
OR (([Extent1].[Logger] = 'PlusService')
AND ('PlusService' IS NOT NULL))) AS [GroupBy1]
but is very slow, average 5 minutes with litle where. I need using where clausule. Is there possible how i can using system count methods like this ?
SELECT CONVERT(bigint, rows)
FROM sysindexes
WHERE id = OBJECT_ID('Log')
AND indid < 2
or this
SELECT CAST(p.rows AS float)
FROM sys.tables AS tbl
INNER JOIN sys.indexes AS idx ON idx.object_id = tbl.object_id and idx.index_id < 2
INNER JOIN sys.partitions AS p ON p.object_id=CAST(tbl.object_id AS int)
AND p.index_id=idx.index_id
WHERE ((tbl.name=N'Log'
AND SCHEMA_NAME(tbl.schema_id)='dbo'))
or this
SELECT SUM (row_count)
FROM sys.dm_db_partition_stats
WHERE object_id=OBJECT_ID('Log')
AND (index_id=0 or index_id=1);
These three options I mentioned above are very fast. But I think it does not support using where clause. Is there any way that I can use methods like this?
I have a view that gets the status for each category for each venue.
I need to display all of the above, but only the latest in the status for each category for each venue.
A general idea could be, for each item in a shop, there is a status. So for the cucumbers, letters, and tomatoes in shop A, the status would be good good bad respectively. Same for shop B, C etc. Now these statuses can be updated at any time - but only the latest update should be displayed.
I have tried to create a view such as the following:
SELECT
dbo.vwVenues.HospitalID
, dbo.vwVenues.Hospital AS hospitalName
, dbo.tblVenueStatus.id AS statusId
, dbo.tblVenueStatusName.statusName
, dbo.tblVenueStatusCategories.categoryName
, dbo.tblVenueStatus.dateAdded AS statusDateAdded
, dbo.tblVenueStatus.loggedBy AS statusLoggedBy
, dbo.tblVenueStatusNotes.noteContent
, dbo.tblVenueStatusNotes.dateAdded AS noteDateAdded
, dbo.tblVenueStatusNotes.removed AS noteRemoved
, dbo.tblVenueStatus.resolved AS statusResolved
, dbo.tblVenueStatus.resolveDate AS statusResolveDate
, dbo.tblVenueStatus.removed AS statusRemoved
, dbo.tblVenueStatus.dateRemoved AS statusRemovedDate
, dbo.tblVenueStatus.categoryId
FROM
dbo.tblVenueStatusName
RIGHT OUTER JOIN dbo.tblVenueStatusNotes
RIGHT OUTER JOIN dbo.tblVenueStatus
ON dbo.tblVenueStatusNotes.id = dbo.tblVenueStatus.noteId
LEFT OUTER JOIN dbo.tblVenueStatusCategories
ON dbo.tblVenueStatus.categoryId = dbo.tblVenueStatusCategories.id
ON dbo.tblVenueStatusName.id = dbo.tblVenueStatus.statusNameId
FULL OUTER JOIN dbo.vwVenues
ON dbo.tblVenueStatus.venuId = dbo.vwVenues.HospitalID
I get all the venues, but I get all the statuses for each category, instead of just the latest. Even trying to phrase the question right was hard - so my current search yeilded nothing.
Could anyone please help?
Edit
CREATE TABLE [dbo].[tblVenueStatus](
[id] [int] IDENTITY(1,1) NOT NULL,
[statusNameId] [int] NOT NULL,
[venuId] [int] NOT NULL,
[categoryId] [int] NOT NULL,
[loggedBy] [nvarchar](50) NOT NULL,
[noteId] [int] NOT NULL,
[dateAdded] [datetime] NOT NULL,
[resolved] [tinyint] NOT NULL,
[resolveDate] [datetime] NULL,
[removed] [tinyint] NOT NULL,
[dateRemoved] [datetime] NULL,
CONSTRAINT [PK_tblSiteVenuStatus] PRIMARY KEY CLUSTERED
CREATE TABLE [dbo].[tblVenueStatusCategories](
[id] [int] IDENTITY(1,1) NOT NULL,
[categoryName] [nvarchar](50) NOT NULL,
[categoryDescription] [nvarchar](150) NULL,
CONSTRAINT [PK_tblVenueStatusCategories] PRIMARY KEY CLUSTERED
CREATE TABLE [dbo].[tblVenueStatusName](
[id] [int] IDENTITY(1,1) NOT NULL,
[statusName] [nvarchar](50) NOT NULL,
[statusDescription] [nchar](150) NULL,
CONSTRAINT [PK_tblVenuStatusName] PRIMARY KEY CLUSTERED
CREATE TABLE [dbo].[tblVenueStatusNotes](
[id] [int] IDENTITY(1,1) NOT NULL,
[noteContent] [nvarchar](500) NULL,
[dateAdded] [datetime] NOT NULL,
[removed] [tinyint] NOT NULL,
[dateRemoved] [datetime] NULL,
CONSTRAINT [PK_tblVenueStatusNotes] PRIMARY KEY CLUSTERED
Desired Output will be:
Venu Name | Category 1 Status | Category 2 Status
Try something like this. It's largely sumerised because of what you said you needed to see in your sample. Try this and let me know if it helps. You can add other columns you need here, It is taking the latest status in each category for each hospital, and showing all hospitals and categories in a easily readable grid.
SELECT * FROM
(
SELECT VwV.HospitalID, vwV.Hospital, ISNULL(vStatusName.statusName, '') AS statusName, vStatusCategories.categoryName
FROM
(
SELECT topStatus.HospitalID, topStatus.categoryId, sta2.id
FROM
(
SELECT HospitalID, categoryId, MAX(sta.dateAdded) AS DateAdded
FROM vwVenues
INNER JOIN tblVenueStatus sta ON sta.venuId = dbo.vwVenues.HospitalID
GROUP BY HospitalID, categoryId
) topStatus
INNER JOIN tblVenueStatus sta2 ON sta2.dateAdded = topStatus.DateAdded AND sta2.venuId = topStatus.HospitalID) Statuss
FULL OUTER JOIN vwVenues vwV ON vwV.HospitalID = Statuss.HospitalID
LEFT OUTER JOIN tblVenueStatus vStatus ON vStatus.id = Statuss.id
LEFT OUTER JOIN tblVenueStatusName vStatusName ON vStatusName.id = vStatus.statusNameId
LEFT OUTER JOIN tblVenueStatusCategories vStatusCategories ON vStatus.categoryId = vStatusCategories.id AND vStatusName.id = vStatus.statusNameId
LEFT OUTER JOIN tblVenueStatusNotes vStatusNotes ON vStatusNotes.id = vStatus.noteId
) AS s
PIVOT (MIN(StatusName)
FOR [CategoryName] IN ([Category1],[Category2])) AS PTbl
Long time reader, first time caller, and all that...
Here's the business problem: a user makes one or more requests for documents. At some later time, a document is uploaded to the system. If that document matches one or more of the requests, the document request is fulfilled. So, there could be one or many requests for Document A, for instance. When Document A is uploaded, all of the requests for Document A are fulfilled.
And here's my technical problem: I've got an AFTER INSERT trigger on the table where the upload of the document is recorded. It checks the DocumentRequest table and updates each row that matches the uploaded document. If only one row matches (only one request for Document A), everything is hunky-dory. If, however, more than one matches, the UPDATE statement in the trigger fails -- I see this error:
Subquery returned more than 1 value.
This is not permitted when the
subquery follows =, !=, <, <= , >, >=
or when the subquery is used as an
expression.
Here are the CREATE statements for the relevant tables:
CREATE TABLE [dbo].[DocumentRequest](
[DocumentRequestId] [int] IDENTITY(1,1) NOT NULL,
[BatchID] [int] NULL,
[CertificateNum] [varchar](20) NOT NULL,
[RequestedTypCd] [varchar](5) NULL,
[RequestedReason] [varchar](60) NULL,
[DestinationTypCd] [varchar](5) NULL,
[DocumentPackageTypCd] [varchar](5) NULL,
[RequestedDtm] [datetime] NOT NULL,
[RequestNotes] [varchar](1000) NULL,
[RequestStatusTypCd] [varchar](5) NOT NULL,
[InactiveFlag] [char](1) NULL,
[CreationDtm] [datetime] NOT NULL,
[CreationUserID] [varchar](10) NOT NULL,
[CompletedDtm] [datetime] NULL,
[CompletedUserID] [varchar](10) NULL,
[ModifiedDtm] [datetime] NULL,
[ModifiedUserID] [varchar](10) NULL,
CONSTRAINT [XPKDocumentRequest] PRIMARY KEY NONCLUSTERED
(
[DocumentRequestId] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
--------------
CREATE TABLE [dbo].[DocumentRequestContents](
[DocumentTypCd] [varchar](5) NOT NULL,
[CreationDtm] [datetime] NOT NULL,
[CreationUserID] [varchar](10) NOT NULL,
[DocumentRequestId] [int] NOT NULL,
[DocumentReceivedDtm] [datetime] NULL,
[DocumentReceivedFlag] [char](1) NULL,
[DocumentIgnoreFlag] [char](1) NULL,
CONSTRAINT [XPKDocumentRequestContents] PRIMARY KEY NONCLUSTERED
(
[DocumentRequestId] ASC,
[DocumentTypCd] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
--------------
CREATE TABLE [dbo].[DocumentStorage](
[DocumentStorageID] [int] IDENTITY(1,1) NOT NULL,
[CertificateNum] [varchar](10) NULL,
[DocumentHandleID] [int] NULL,
[DocumentTypVal] [varchar](100) NULL,
[CreationDtm] [datetime] NULL,
[CreationUserID] [varchar](10) NULL,
[lastupd_user] [varchar](8) NULL,
[lastupd_stamp] [datetime] NULL,
[DocumentNam] [varchar](100) NULL,
PRIMARY KEY NONCLUSTERED
(
[DocumentStorageID] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
--------------
CREATE TABLE [dbo].[DocumentProfile](
[DocumentProfileID] [int] IDENTITY(1,1) NOT NULL,
[DocumentTypCd] [varchar](5) NULL,
[DocumentVersionNum] [varchar](10) NULL,
[DocumentApproveInd] [varchar](1) NULL,
[CreationDtm] [datetime] NULL,
[CreationUserID] [varchar](10) NULL,
[lastupd_stamp] [datetime] NULL,
[lastupd_user] [varchar](8) NULL,
[DocumentStorageTypVal] [varchar](100) NULL,
[MIMETypVal] [varchar](50) NULL,
[DocumentSourceTypCd] [varchar](5) NULL,
[DocumentFormatTypCd] [varchar](5) NULL,
[DocumentReceiveLocationTypCd] [varchar](5) NULL,
[DocumentIndexTypCd] [varchar](5) NULL,
[DocumentNam] [varchar](100) NULL,
[DocumentTrackedInd] [char](1) NULL CONSTRAINT [DF_DocumentProfile_DocumentTrackedInd] DEFAULT ('N'),
PRIMARY KEY NONCLUSTERED
(
[DocumentProfileID] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
And the trigger...
CREATE TRIGGER [trg_DMTDocumentReceived_DocumentStorage]
ON [dbo].[DocumentStorage]
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON;
UPDATE DocumentRequestContents
SET DocumentRequestContents.DocumentReceivedFlag = 'Y',
DocumentRequestContents.DocumentReceivedDtm = getdate()
FROM
DocumentRequestContents
INNER JOIN DocumentRequest
ON DocumentRequestContents.DocumentRequestId = DocumentRequest.DocumentRequestId
INNER JOIN DocumentProfile
ON DocumentRequestContents.DocumentTypCd = DocumentProfile.DocumentTypCd
INNER JOIN Inserted
ON DocumentProfile.DocumentStorageTypVal = Inserted.DocumentTypVal
WHERE
(DocumentRequestContents.DocumentReceivedFlag <> 'Y' OR
DocumentRequestContents.DocumentReceivedFlag IS NULL)
AND (DocumentRequest.InactiveFlag IS NULL)
AND (DocumentRequest.CertificateNum = Inserted.CertificateNum)
AND (DocumentProfile.DocumentStorageTypVal = Inserted.DocumentTypVal)
END
I'm at a bit of a loss as to where to go from here. Can you give a guy a hand?
EDIT:
A request can have more than one document, so the table that is being updated in the trigger (DocumentRequestContents) also has a trigger on it, which determines if the entire request has been fulfilled. As far as I can tell, it does not have a subquery, either, but here it is:
CREATE TRIGGER [trg_DMTDocumentReceived_CompletenessCheck]
ON [dbo].[DocumentRequestContents]
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON;
DECLARE #TotalDocs int, #ReceivedDocs int
IF UPDATE(DocumentReceivedFlag)
BEGIN
IF (SELECT DocumentReceivedFlag FROM Inserted) = 'Y' AND (SELECT DocumentReceivedFlag FROM Deleted) = 'N'
BEGIN
SELECT #TotalDocs = count(*)
FROM DocumentRequestContents
INNER JOIN Inserted
ON DocumentRequestContents.DocumentRequestID = Inserted.DocumentRequestID
WHERE (DocumentRequestContents.DocumentIgnoreFlag <> 'Y' OR DocumentRequestContents.DocumentIgnoreFlag IS NULL)
SELECT #ReceivedDocs = count(*)
FROM DocumentRequestContents
INNER JOIN Inserted
ON DocumentRequestContents.DocumentRequestID = Inserted.DocumentRequestID
WHERE DocumentRequestContents.DocumentReceivedFlag = 'Y'
IF (#ReceivedDocs = #TotalDocs)
BEGIN
UPDATE DocumentRequest
SET RequestStatusTypCd = 'CMPLT',
CompletedDtm = getdate(),
CompletedUserID = 'SYSTEM',
ModifiedDtm = getdate(),
ModifiedUserID = 'SYSTEM'
FROM DocumentRequest
INNER JOIN Inserted
ON DocumentRequest.DocumentRequestId = Inserted.DocumentRequestId
END
END
END
END
Thanks,
Jason
The offending line appears to be here:
IF (SELECT DocumentReceivedFlag FROM Inserted) = 'Y' AND
(SELECT DocumentReceivedFlag FROM Deleted) = 'N' ...
This is essentially a "subquery". The IF statement is written with the expectation that there will only be one row in both inserted and deleted. Without knowing the details of what the business logic is here, I can only speculate, but most likely you'll be OK if you just rewrite that as:
IF EXISTS(SELECT 1 FROM inserted WHERE DocumentReceivedFlag = 'Y') AND
EXISTS(SELECT 1 FROM deleted WHERE DocumentReceivedFlag = 'N'))
But it might be more complicated than that... it could be that you actually need to join the inserted to deleted rows and check if the flag has actually changed from 'Y' to 'N'.
Check if you don't have a trigger on DocumentRequestContents as well.
On re-reading, the obvious problem is this part of the second trigger:
IF (SELECT DocumentReceivedFlag FROM Inserted) = 'Y'
AND (SELECT DocumentReceivedFlag FROM Deleted) = 'N'
This would fail if multiple rows where inserted, because SQL Server expects both of these subqueries to return one or no rows.
By the way, I personally avoid triggers at any cost. They introduce too much complexity for me to handle.
You may want to try aliasing the Inserted table in your join. While I haven't experienced this myself, it may be attempting to perform a subquery in your WHERE clause rather than using the joined table.
Your trigger doesn't appear to have a sub-query anywhere in it - this is the only trigger on your table? This error isn't caused by a join or a multi-row update, so I'm at a loss as to why your trigger would be generating this error.
Do you get the error when you're attempting the insert into the table itself? Perhaps it's actually the query you're using to insert that's failing - please post that insert statement as well.