Im trying to run OPENQUERY on a linked server without much success. I have 2 queries that are using a UNION operator. They run fine seperately and together when running them as a normal query. I am getting the following message when i try and run them via open query.
OLE DB provider "SQLNCLI11" for linked server "IIS900011" returned message "Deferred prepare could not be completed."
Msg 8180, Level 16, State 1, Line 1
Statement(s) could not be prepared.
Msg 102, Level 15, State 1, Line 35
Incorrect syntax near 'time'.
Msg 102, Level 15, State 1, Line 13
Incorrect syntax near 'Monday'.
My query is as follows:
SELECT *
FROM OPENQUERY(IIS900011,
'select
sysjobs.name job_name
,sysjobs.enabled job_enabled
,sysschedules.name schedule_name
,sysschedules.freq_recurrence_factor
,case
when freq_type = 4 then ''Daily''
end frequency
,
''every '' + cast (freq_interval as varchar(3)) + '' day(s)'' Days
,
case
when freq_subday_type = 2 then '' every '' + cast(freq_subday_interval as varchar(7))
+ '' seconds'' + '' starting at ''
+ stuff(stuff(RIGHT(replicate(''0'', 6) + cast(active_start_time as varchar(6)), 6), 3, 0, '':''), 6, 0, '':'')
when freq_subday_type = 4 then '' every '' + cast(freq_subday_interval as varchar(7))
+ '' minutes'' + '' starting at ''
+ stuff(stuff(RIGHT(replicate(''0'', 6) + cast(active_start_time as varchar(6)), 6), 3, 0, '':''), 6, 0, '':'')
when freq_subday_type = 8 then '' every '' + cast(freq_subday_interval as varchar(7))
+ '' hours'' + '' starting at ''
+ stuff(stuff(RIGHT(replicate(''0'', 6) + cast(active_start_time as varchar(6)), 6), 3, 0, '':''), 6, 0, '':'')
else '' starting at ''
+stuff(stuff(RIGHT(replicate(''0'', 6) + cast(active_start_time as varchar(6)), 6), 3, 0, '':''), 6, 0, '':'')
end time
from msdb.dbo.sysjobs
inner join msdb.dbo.sysjobschedules on sysjobs.job_id = sysjobschedules.job_id
inner join msdb.dbo.sysschedules on sysjobschedules.schedule_id = sysschedules.schedule_id
where freq_type = 4')
UNION
SELECT *
FROM OPENQUERY(IIS900011,
'select
sysjobs.name job_name
,sysjobs.enabled job_enabled
,sysschedules.name schedule_name
,sysschedules.freq_recurrence_factor
,case
when freq_type = 8 then ''Weekly''
end frequency
,
replace
(
CASE WHEN freq_interval&1 = 1 THEN ''Sunday, '' ELSE '' END
+CASE WHEN freq_interval&2 = 2 THEN ''Monday, '' ELSE '' END
+CASE WHEN freq_interval&4 = 4 THEN ''Tuesday, '' ELSE '' END
+CASE WHEN freq_interval&8 = 8 THEN ''Wednesday, '' ELSE '' END
+CASE WHEN freq_interval&16 = 16 THEN ''Thursday, '' ELSE '' END
+CASE WHEN freq_interval&32 = 32 THEN ''Friday, '' ELSE '' END
+CASE WHEN freq_interval&64 = 64 THEN ''Saturday, '' ELSE '' END
,'', ''
,''
) Days
,
case
when freq_subday_type = 2 then '' every '' + cast(freq_subday_interval as varchar(7))
+ '' seconds'' + '' starting at ''
+ stuff(stuff(RIGHT(replicate(''0'', 6) + cast(active_start_time as varchar(6)), 6), 3, 0, '':''), 6, 0, '':'')
when freq_subday_type = 4 then '' every '' + cast(freq_subday_interval as varchar(7))
+ '' minutes'' + '' starting at ''
+ stuff(stuff(RIGHT(replicate(''0'', 6) + cast(active_start_time as varchar(6)), 6), 3, 0, '':''), 6, 0, '':'')
when freq_subday_type = 8 then '' every '' + cast(freq_subday_interval as varchar(7))
+ '' hours'' + '' starting at ''
+ stuff(stuff(RIGHT(replicate(''0'', 6) + cast(active_start_time as varchar(6)), 6), 3, 0, '':''), 6, 0, '':'')
else '' starting at ''
+ stuff(stuff(RIGHT(replicate(''0'', 6) + cast(active_start_time as varchar(6)), 6), 3, 0, '':''), 6, 0, '':'')
end time
from msdb.dbo.sysjobs
inner join msdb.dbo.sysjobschedules on sysjobs.job_id = sysjobschedules.job_id
inner join msdb.dbo.sysschedules on sysjobschedules.schedule_id = sysschedules.schedule_id
where freq_type = 8
order by job_enabled desc')
I think im having a bit of a brain melt here as i cant see where the syntax error is, or if it is indeed a red herring. I havent used openquery much before so its probably something obvious i've missed.
EDIT: I had missed some punctuation. Think im sorted now.
CASE WHEN freq_interval&1 = 1 THEN ''Sunday, '' ELSE '''' END
+CASE WHEN freq_interval&2 = 2 THEN ''Monday, '' ELSE '''' END
+CASE WHEN freq_interval&4 = 4 THEN ''Tuesday, '' ELSE '''' END
+CASE WHEN freq_interval&8 = 8 THEN ''Wednesday, '' ELSE '''' END
+CASE WHEN freq_interval&16 = 16 THEN ''Thursday, '' ELSE '''' END
+CASE WHEN freq_interval&32 = 32 THEN ''Friday, '' ELSE '''' END
+CASE WHEN freq_interval&64 = 64 THEN ''Saturday, '' ELSE '''' END
Related
I have structure like that(as example):
ID ClassId Name Parent
--------------------------------------
1 12 Boss
2 13 Manager1 1
3 13 Manager2 1
4 13 Manager3 1
5 14 SubManager1 3
6 15 UnderSubManager1 5
7 16 Worker1 2
8 16 Worker2 6
9 14 SubManager2 4
10 16 Worker3 9
Than, we have this:
Boss->Manager1->Worker1
Boss->Manager2->SubManager1->UnderSubManager1->Worker2
Boss->Manager3->SubManager2->Worker3
I need query, that give me a this reult:
Boss->Manager1->worker1
Boss->Manager2->worker2
Boss->Manager3->worker3
I try do this witch CTE using ClassId but with poor result :(
Assuming you want to show the 2 top levels (Boss, and ManagerX), and then the lowest level (WorkerX) -
create table #tmp (ID int, ClassID int, Name varchar(32), Parent int)
go
insert into #tmp (ID, ClassID, Name, Parent)
values
(1, 12, 'Boss', null)
, (2, 13, 'Manager1', 1)
, (3, 13, 'Manager2', 1)
, (4, 13, 'Manager3', 1)
, (5, 14, 'SubManager1', 2)
, (6, 15, 'UnderSubManager1', 5)
, (7, 16, 'Worker1', 2)
, (8, 16, 'Worker2', 6)
, (9, 14, 'SubManager2', 4)
, (10, 16, 'Worker3', 9)
go
with cte as (
select t.ID, t.ClassID, t.Name, t.Parent
, Path = cast(case when t.ClassID in (12, 13) then t.Name else '' end as varchar(max))
, NestLevel = 0
, IsWorker = case t.ClassID when 16 then 1 else 0 end
from #tmp t
where t.Parent is null
union all
select t.ID, t.ClassID, t.Name, t.Parent
, Path = cte.Path + cast(case when t.ClassID in (12, 13, 16) then '->' + t.Name else '' end as varchar(max))
, NestLevel = cte.NestLevel + 1
, IsWorker = case t.ClassID when 16 then 1 else 0 end
from #tmp t
inner join cte on t.Parent = cte.ID
)
select cte.Path
from cte
where cte.IsWorker = 1
order by cte.Path
drop table #tmp
go
The result:
Boss->Manager1->Worker1
Boss->Manager1->Worker2
Boss->Manager3->Worker3
Please consider the following tables. They describe a schools' hierarchy and the notes per student.
users
-------------------------------------------------------------
root_id obj_id obj_type obj_ref_id obj_role
-------------------------------------------------------------
1 2 student 7 learn
1 3 student 7 learn
1 1 principal 1 lead
1 4 mentor 1 train teachers
1 5 trainee 4 learn teaching
1 6 trainee 4 learn teaching
1 7 teacher 1 teach
2 8 student 9 learn
2 9 principal 9 lead
notes
--------------------------------------------------------------
note_id obj_id note
--------------------------------------------------------------
1 2 foo
2 2 bar
3 2 baz
4 3 lorem
5 8 ipsum
I need to write out the hierarchy and number of notes per user as follows:
-------------------------------------------------------------------------------------------
obj_id notes obj_path
-------------------------------------------------------------------------------------------
1 0 principal 1 (lead)
2 3 student 2 (learn) > teacher 7 (teach) > principal 1 (lead)
3 1 student 3 (learn) > teacher 7 (teach) > principal 1 (lead)
4 0 mentor 4 (train teachers) > principal 1 (lead)
5 0 trainee 5 (learn teaching) > mentor 4 (train teachers) > principal 1 (lead)
6 0 trainee 6 (learn teaching) > mentor 4 (train teachers) > principal 1 (lead)
7 0 teacher 7 (teach) > principal 1 (lead)
8 1 student 8 (learn) > principal 2 (lead)
9 0 principal 9 (lead)
For this, I understand that I need to use a loop as follows:
declare cur cursor for
select obj_id from users order by root_id
open cur
declare #obj_id int
fetch next from cur into #id
while (##FETCH_STATUS = 0)
begin
select obj_role from users where obj_id = #obj_id
fetch next from cur into #obj_id
end
close cur
deallocate cur
This is what I have until now, but I do not understand how to go from here. Can someone help me on my way?
Understand that using a cursor is going to process each individual record one by one.
Recursive CTE would be a better solution:
Sql server CTE and recursion example
CTE Recursion to get tree hierarchy
How does a Recursive CTE run, line by line?
Something like:
DECLARE #User TABLE
(
[root_id] INT
, [obj_id] INT
, [Obj_type] NVARCHAR(100)
, [obj_ref_id] INT
, [obj_role] NVARCHAR(100)
);
DECLARE #Notes TABLE
(
[note_id] INT
, [obj_id] INT
, [note] NVARCHAR(255)
);
INSERT INTO #Notes (
[note_id]
, [obj_id]
, [note]
)
VALUES ( 1, 2, 'foo ' )
, ( 2, 2, 'bar ' )
, ( 3, 2, 'baz ' )
, ( 4, 3, 'lorem' )
, ( 5, 8, 'ipsum' );
INSERT INTO #User (
[root_id]
, [obj_id]
, [Obj_type]
, [obj_ref_id]
, [obj_role]
)
VALUES ( 1, 2, 'student', 7, 'learn' )
, ( 1, 3, 'student', 7, 'learn' )
, ( 1, 1, 'principal', 1, 'lead' )
, ( 1, 4, 'mentor', 1, 'train teachers' )
, ( 1, 5, 'trainee', 4, 'learn teaching' )
, ( 1, 6, 'trainee', 4, 'learn teaching' )
, ( 1, 7, 'teacher', 1, 'teach' )
, ( 2, 8, 'student', 9, 'learn' )
, ( 2, 9, 'principal', 9, 'lead' );
WITH [Hierarchy]
AS ( SELECT [obj_id] AS [root_obj]
, [obj_ref_id] AS [root_obj_ref]
, [obj_id]
, [obj_ref_id]
, CONVERT(
NVARCHAR(MAX)
, [Obj_type] + ' ' + CONVERT(NVARCHAR, [obj_id]) + ' ('
+ [obj_role] + ')'
) AS [obj_path]
FROM #User
UNION ALL
SELECT [a].[root_obj]
, [a].[root_obj_ref]
, [b].[obj_id]
, [b].[obj_ref_id]
, [a].[obj_path] + ' > ' + [b].[Obj_type]
+ CONVERT(NVARCHAR, [b].[obj_id]) + ' (' + [b].[obj_role] + ')' AS [obj_path]
FROM [Hierarchy] [a]
INNER JOIN #User [b]
ON [b].[obj_id] = [a].[obj_ref_id]
WHERE [a].[obj_id] <> [a].[obj_ref_id] ) --Here, basically continue the recursion while the record isn't referencing itself. The final will include that self referencing record.
SELECT [Hierarchy].[root_obj] AS [obj_id]
, (
SELECT COUNT(*)
FROM #Notes
WHERE [obj_id] = [Hierarchy].[root_obj]
) AS [notes] --Here we'll go out and get the count of notes.
, [Hierarchy].[obj_path]
FROM [Hierarchy]
WHERE [Hierarchy].[obj_id] = [Hierarchy].[obj_ref_id] --Then we only went those records built up to the final record that was referencing itself.
ORDER BY [Hierarchy].[root_obj];
I know I'm gonna 'kick myself' when I see the answer but right now I can't see it.
SELECT [faxdate]
,DATEDIFF(day,
CAST(SUBSTRING(RPT.FaxDate, 1, 4) + '-' + SUBSTRING(RPT.FaxDate, 5, 2) + '-' + SUBSTRING(RPT.FaxDate, 7, 2) AS DATE), getdate()) AS vDiff
faxdate vDiff 20130704 62 20130705 61
20130705 61 20130708 58
Works great, but I want to be able to test the number of days Eg. records over 60 days.
When I add this :
WHERE (DATEDIFF(day,
CAST(SUBSTRING(RPT.FaxDate, 1, 4) + '-' + SUBSTRING(RPT.FaxDate, 5, 2) + '-' + SUBSTRING(RPT.FaxDate, 7, 2) AS DATE), getdate()) >60)
I get: Conversion failed when converting date and/or time from character string.
I have also tried this sql as a derived table and then tested vDiff ....i'm obviously not doing it right
any help would be appreciated
ttfn
Martyn
(Cornwall England and it's not raining .. result !)
Try
SELECT [faxdate],DAY(DATEDIFF(CAST(SUBSTRING(RPT.FaxDate, 1, 4) + '-' +
SUBSTRING(RPT.FaxDate, 5, 2) + '-' + SUBSTRING(RPT.FaxDate, 7, 2) AS DATE),
getdate())) AS vDiff
instead of using where, use having like below
HAVING vDiff > 60
I am using SSRS 2008 and i have a stored proc which currently uses cursors to delete and add data, but even after I convert this to select queries, I am getting error:
Msg 102, Level 15, State 1, Line 39
Incorrect syntax near ')'.
Here was the original Cursor which worked:
OPEN PARTS
FETCH PARTS INTO #PART_NUM,
#PART_DESC
SET #PARTS_FETCH = ##FETCH_STATUS
WHILE #PARTS_FETCH = 0 BEGIN
SET #THE_DATE = dateadd("yy", -1, dateadd("m", -1, getdate()))
SET #END_DATE = DATEADD(ms, -5, DATEADD(mm, DATEDIFF(m, 0, getdate()) + 1, 0))
-- Get PL for part number
Delete from #tbl_PL
Insert #tbl_PL
SELECT FRUD.tblXref.product_code FROM FRUD.tblfieldOrderablePart INNER JOIN
FRUD.MAX_APPROVED ON FRUD.tblfieldOrderablePart.fop_no = FRUD.MAX_APPROVED.fop_no AND
FRUD.tblfieldOrderablePart.fop_revision = FRUD.MAX_APPROVED.MaxOffop_revision INNER JOIN
FRUD.tblXref ON FRUD.MAX_APPROVED.fop_no = FRUD.tblXref.fop_no AND
FRUD.MAX_APPROVED.MaxOffop_revision = FRUD.tblXref.fop_revision
WHERE (dbo.FORMAT_PART(FRUD.tblfieldOrderablePart.fop_no) = dbo.FORMAT_PART(#PART_NUM))
-- End Get PL
WHILE #THE_DATE <= #END_DATE BEGIN
SET #THE_DATE = DATEADD(ms, -5, DATEADD(mm, DATEDIFF(m, 0, #THE_DATE) + 1, 0))
-- Get census using PL
SELECT #ALL_TOTAL = SUM(TheSum) FROM (SELECT CAST(RELIABILITY.Census.Census AS DECIMAL(9,2)) AS TheSum, (CONVERT(datetime, LEFT(CONVERT(char, Period), 4) + '-' + RIGHT(Period, 2) + '-1', 102)) as ThePeriod
FROM RELIABILITY.Census
WHERE RELIABILITY.Census.PL In (Select distinct * FROM #tbl_PL)
AND (CONVERT(datetime, LEFT(CONVERT(char, Period), 4) + '-' + RIGHT(Period, 2) + '-1', 102) >=
DATEADD(mm, DATEDIFF(mm, 0, #THE_DATE) - 5, 0)) AND (CONVERT(datetime, LEFT(CONVERT(char, Period), 4)
+ '-' + RIGHT(Period, 2) + '-1', 102) <= #THE_DATE) UNION ALL SELECT CAST(Census AS DECIMAL(9,2)) AS TheSum, Period FROM [MANUAL].SMARTSOLVE_CENSUS WHERE (Period >= DATEADD(mm, DATEDIFF(mm, 0, #THE_DATE) - 5, 0) AND Period <= #THE_DATE) AND (PL In (Select distinct * FROM #tbl_PL)))A
And here is my conversion to Select:
DECLARE #THE_DATE datetime,
#END_DATE datetime,
#THE_GOAL decimal(18,2),
#PART_NUM nvarchar(50),
#UNCHANGED_PART_NUM nvarchar(50),
#PART_DESC varchar(35),
#PARTS_FETCH int,
#NUM_FAILED int,
#AVG_CENSUS decimal(18,2),
#PL_VAR nvarchar(50),
#PL_FETCH int,
#PL_TOTAL decimal(9,2),
#ALL_TOTAL decimal(9,2)
--WHILE #PARTS_FETCH = 0 BEGIN
SET #THE_DATE = dateadd("yy", -1, dateadd("m", -1, getdate()))
SET #END_DATE = DATEADD(ms, -5, DATEADD(mm, DATEDIFF(m, 0, getdate()) + 1, 0))
--WHILE #THE_DATE <= #END_DATE BEGIN
SET #THE_DATE = DATEADD(ms, -5, DATEADD(mm, DATEDIFF(m, 0, #THE_DATE) + 1, 0))
-- Get census using PL
SELECT #ALL_TOTAL = SUM(TheSum) FROM
(SELECT CAST(RELIABILITY.Census.Census AS DECIMAL(9,2)) AS TheSum
from RELIABILITY.Census
WHERE RELIABILITY.Census.PL In (Select distinct * FROM #tbl_PL)
AND (CONVERT(datetime, LEFT(CONVERT(char, Period), 4) + '-' + RIGHT(Period, 2) + '-1', 102) >=
DATEADD(mm, DATEDIFF(mm, 0, #THE_DATE) - 5, 0)) AND (CONVERT(datetime, LEFT(CONVERT(char, Period), 4)+ '-' + RIGHT(Period, 2) + '-1', 102) <= #THE_DATE)
UNION ALL
SELECT CAST(Census AS DECIMAL(9,2)) AS TheSum, Period
FROM [MANUAL].SMARTSOLVE_CENSUS
WHERE (Period >= DATEADD(mm, DATEDIFF(mm, 0, #THE_DATE) - 5, 0) AND Period <= #THE_DATE) AND (PL In (Select distinct * FROM #tbl_PL))
))A
As Joel and Lamak pointed out you have an extra ) This is actually really easy to find if you use something like Instant SQL formatter This will give the error
)(11,3) expected token:Unknown
)(11,3) expected token:
It also formats the SQL as below which makes it a little easier to follow.
SELECT #ALL_TOTAL = SUM(thesum)
FROM (SELECT CAST(reliability.census.census AS DECIMAL(9, 2)) AS thesum
FROM reliability.census
WHERE reliability.census.pl IN (SELECT DISTINCT *
FROM #tbl_pl)
AND ( CONVERT(DATETIME, LEFT(CONVERT(CHAR, period), 4) + '-' +
RIGHT(
period, 2)
+
'-1'
, 102) >= Dateadd(mm, Datediff(mm, 0, #THE_DATE) - 5, 0) )
AND ( CONVERT(DATETIME, LEFT(CONVERT(CHAR, period), 4)+ '-' +
RIGHT(
period, 2) +
'-1',
102) <= #THE_DATE )
UNION ALL
SELECT CAST(census AS DECIMAL(9, 2)) AS thesum,
period
FROM [MANUAL].smartsolve_census
WHERE ( period >= Dateadd(mm, Datediff(mm, 0, #THE_DATE) - 5, 0)
AND period <= #THE_DATE )
AND ( pl IN (SELECT DISTINCT *
FROM #tbl_pl) ))a
Sounds like you have mis-matched parentheses, double check and make sure they all line up correctly. You have one more ")" at the end of that last select statement than you have ever being opened. That's a lot of nesting! Make sure everything matches up how you intended, or you may get unexpected results if your UNION gets applied at the wrong level or something.
If I'm reading your query correctly, you have two errors. The first is an extra ")" on the last line, it should be:
WHERE (Period >= DATEADD(mm, DATEDIFF(mm, 0, #THE_DATE) - 5, 0) AND Period <= #THE_DATE) AND (PL In (Select distinct * FROM #tbl_PL))
) A
And, I think you also have more columns on your query after the UNION ALL, you are selecting CAST(Census AS DECIMAL(9,2)) AS TheSum, Period and on the first one you are selecting only one column: CAST(RELIABILITY.Census.Census AS DECIMAL(9,2)) AS TheSum
I have three variables :-
#ScoreA DECIMAL(10,7)
#ScoreB DECIMAL(10,7)
#ScoreC DECIMAL(10,7)
#FinalScore DECIMAL(10, 7)
I wish to get the average of the three scores. BUT 1, 2 or all 3 values might be zero.
Eg. scenarios:
A = 1.4, B=3.5, C=5.0; FinalScore = 3.3
A = 0.0, B=0.0, C=0.0; FinalScore = 0.0
A = 1.1, B=0.0, C=0.0; FinalScore = 1.1
A = 0.0, B=2.0, C=4.8; FinalScore = 3.4
Cheers!
IF #A > 0 OR #B > 0 OR #C > 0
SELECT ((#A + #B + #C) /
(0 +
CASE WHEN #A = 0 THEN 0 ELSE 1 END +
CASE WHEN #B = 0 THEN 0 ELSE 1 END +
CASE WHEN #C = 0 THEN 0 ELSE 1 END ))
ELSE
SELECT 0.0
EDIT
Modified query to now handle divide by zero scenario's.
EDIT2
Here is "the trick with the AVG(..) function" :) with Common Table Expression
WITH T(I) AS (SELECT #A UNION SELECT #B UNION SELECT #C)
SELECT AVG(I) FROM T
WHERE I > 0
SELECT ((#A + #B + #C) /
(CASE WHEN (#A = 0.0 AND #B = 0.0 AND #C = 0.0) THEN 1 ELSE 0 END
+ CASE WHEN #A = 0 THEN 0 ELSE 1 END
+ CASE WHEN #B = 0 THEN 0 ELSE 1 END
+ CASE WHEN #C = 0 THEN 0 ELSE 1 END
)
)
For me this is easier to read and understand:
DECLARE
#ScoreA DECIMAL(10,7),
#ScoreB DECIMAL(10,7),
#ScoreC DECIMAL(10,7),
#FinalScore DECIMAL(10, 7)
SET #ScoreA = 1.4
SET #ScoreB = 3.5
SET #ScoreC = 5.0
DECLARE
#AVG TABLE (value DECIMAL(10,7))
INSERT INTO #AVG
SELECT #ScoreA WHERE #ScoreA > 0
UNION
SELECT #ScoreB WHERE #ScoreB > 0
UNION
SELECT #ScoreC WHERE #ScoreC > 0
SELECT COALESCE(AVG(value), 0) FROM #AVG