Showing posts with label task. Show all posts
Showing posts with label task. Show all posts

Friday, March 30, 2012

Recovery Model to be used for a Data Flow Task

Hello there

I have a SSIS 2005 DTSX Package which has several Data flow tasks which directly dump data between tables from 2 different databases.

Suppose if my destination database is named, DestinationDB, what recovery model should I select for this database so that my ldf file size does not explode? I want to keep the ldf file as small in size as possible.

  1. Currently I have used Simple Recovery model, and the ldf file size goes to around 80 GB. (Inserting around 200 million rows)

  2. Will Bulk Logged model be a better option?

Also what does a SSIS 2005 Data flow task use internally? (Insert operation or some sort of Bulk Insert between DBs)

Please help.

The fast load option on the OLE DB destination performs a bulk load.|||

Thanks for the response.

Does the fast load option keep the ldf file size to a minimum?

|||This probably isn't the correct forum for you, but I believe you'll want "bulk-logged recovery" so as not to grow the LDF file. Or split your data into smaller chunks using the MaximumInsertCommitSize setting on the OLE DB Destination.

Wednesday, March 7, 2012

Recordset Modification and Copy

Please Help.

I have written a custom DTS task in an ActiveX Script. My script creates three recordsets from three existing tables in an SQL Server 2k DB by copying all the data in these tables.

My script then modifies the data in these recordsets including dropping several records, creates a new table and inserts the modified data into the new table.

Unfortunately, I need to keep my original data unmodified...and currently my code changes my original data when it modifies the record sets.

Does anyone have a method for modifying a recordset without modifying the source data? I am writing my ActiveX Script through the VB scripting language.

From what I have read on the internet some people suggest creating a new recordset, copying the data from the original recordset to the new recordset, and then modify and insert the new recordset. This is supposed to keep my source data unchanged. Unfortunately, I have not been successful with this method mainly because I am having trouble creating a new recordset and copying my original recordset data into this new object.

Thank you in advance for any help or input you might have!!!

-TRocheI assume you are using ADO? Disconnect your recordset by setting your ActiveConnection property to nothing.|||I don't think this will work. You see I have to manipulate the data through several DO Until loops. The constraint on my DO loop is

"DO UNTIL rs.EOF"

Before I set the recordset ActiveConnection to nothing It tells me I have to first close the recordset. Unfortunately, I can not run the syntax of the above loop if the recrordset is closed, and if I open the recordset with a new connection it again changes my source data.

Does anyone have any additional insight?

Thanks!

-TRoche|||create a function READ UNCOMMITTED transaction isolation level (you can do it with nolock optimizer hint) and do your DO UNTIL against the rs that points to it.|||Wow...I am just a beginner at this stuff...I will look into it, but do you have a sample code for this by chance?

thanks,

TRoche|||create function dbo.fn_select_star_from_your_table (
@.parm1 <data type>,
@.parm2 <data type>,
@.parm3 <data type> ) returns table
as return (
select * from your_table (nolock)
where field1 = @.parm1
and field2 = @.parm2
and @.field3 = parm3)
go|||Hmmmmm....ok to start I am writing a custom DTS Task, using an ActiveX Script in the DTS Designer, coding in VBScript

Well I am having a few problems with the previous comments. First off I can't get the code to drop the function ms_sql_dba advised. Here is my DROP code for a function called FUNSTUFF:

dim Dropx
set Dropx = CreateObject("ADODB.Command")

Dropx = "Drop Function [dbo].[FUNSTUFF]"
connection.execute Dropx

I am only trying to drop the function because if I run the code multiple times it errors saying the the object "FunStuff" already exists in the database...and I looked...and it does...dang Does anyone see something wrong with the above DROP code?

Also, ms_sql_dba, I am not sure I understand what your function does. Here is how I thought to use your advice.

Write a function called ADVICE as follows:
dim ADVICE
set ADVICE = CreateObject("ADODB.Command")

ADVICE = "CREATE FUNCTION dbo.FUNSTUFF (@.time float, @.Position float ) RETURNS Table AS RETURN (select * from GPSy (nolock) where ty = time and GPS_y = Position)"

then:
Open.recordset ADVICE, Connection, adOpenKeyset

Then write my do loop:
DO UNTIL recordset.EOF
blah, blah, blah
Loop

Unfortunately, I run into all kinds of errors like saying the operation can not be performed if the recordset is closed. But if I write an open command like:

open.recordset.connection

I get the error that the function FUNSTUFF alreadyexists in the database.

Hmmmmmmmm...

Does anyone have any advice? Do I have to write the Function code before every loop or a drop code after every loop...or...hmmm...I am just confused about how the function works.

A million thanks to anyone who has any input!!

-TRoche

RecordSet into a DataFlow Task

In the control flow I have an "Execute SQL Task" that executes a stored procedure. The stored procedure returns a result set of about 2000 rows of data into a package variable that has been typed as Object to contain the data.

What I have not been able to figure out is how to access the rows of data (in the package variable) from within a data flow task. There does not seem to be a data flow source task to perform that operation.

What am I missing that would make this easy?

...cordell...

if you need to have control on every row of the result set you may be on the need of using a data flow task(source, transforms and destination components). Would you give an example of what you are trying to accomplish after getting the 2000 rows?

|||

In the data flow task...I need to parse through the data to generate 3 unique result sets of data. One of the result sets will go to a text file, the 2nd result set go back into a staging table, and the 3rd result set goes to a excel spreadsheet.

|||

Cordell Swannack wrote:

In the control flow I have an "Execute SQL Task" that executes a stored procedure. The stored procedure returns a result set of about 2000 rows of data into a package variable that has been typed as Object to contain the data.

What I have not been able to figure out is how to access the rows of data (in the package variable) from within a data flow task. There does not seem to be a data flow source task to perform that operation.

What am I missing that would make this easy?

...cordell...

This shows you how to do it:

Recordsets instead of raw files
(http://blogs.conchango.com/jamiethomson/archive/2006/01/04/2540.aspx)

I'm not sure if this is relevant though. If you are using a SQL statement to get the data why not just put the SQL statement into an OLE DB Source adapter? Why bother with the rigmarole of a variable and then having to write code?

-Jamie

|||

Cordell Swannack wrote:

In the data flow task...I need to parse through the data to generate 3 unique result sets of data. One of the result sets will go to a text file, the 2nd result set go back into a staging table, and the 3rd result set goes to a excel spreadsheet.

I would wager you can accomplish all of this with a combination of the conditional split, multicast and/or derived column components.

Even if you can't, you would be better off employing a script component to parse through the data - there is still no need to put it into a variable first.

-Jamie

|||

Jamie Thomson wrote:

Cordell Swannack wrote:

In the control flow I have an "Execute SQL Task" that executes a stored procedure. The stored procedure returns a result set of about 2000 rows of data into a package variable that has been typed as Object to contain the data.

What I have not been able to figure out is how to access the rows of data (in the package variable) from within a data flow task. There does not seem to be a data flow source task to perform that operation.

What am I missing that would make this easy?

...cordell...

This shows you how to do it:

Recordsets instead of raw files
(http://blogs.conchango.com/jamiethomson/archive/2006/01/04/2540.aspx)

I'm not sure if this is relevant though. If you are using a SQL statement to get the data why not just put the SQL statement into an OLE DB Source adapter? Why bother with the rigmarole of a variable and then having to write code?

-Jamie

I was going to suggest something similar. In general you would use data flows to perform row by row operations; like transformations, splits, sorts, etc. However the control flow may be better place to row set based operations; like an update, select into, etc.

In you particular case, use a dataflow task and then drop a OLE DB source component, any required transform and the detination component.

|||

Helpful suggestions....

While you can use the OLE DB Source adapater inside of the Data Flow task...I am executing a stored procedure that returns back a large result set. When you click on the 'Preview' button...the data and all of the column names are returned. (Just proving that everything works.)

However I haven't figure out how to set the column names typically set by OLE DB Source component. Right now they are blank. Usually at design time when you reference a table or use simple select statement the OLE DB Source task can map the columns specified by the table name or select statement to create a list of columns that are used for the output and thus by other components in the data flow task.

But when executing a stored procedure...the column names are not returned until completion (i.e. runtime) of the stored procedure. This is the problem.

...cordell...

|||

Cordell Swannack wrote:

Helpful suggestions....

While you can use the OLE DB Source adapater inside of the Data Flow task...I am executing a stored procedure that returns back a large result set. When you click on the 'Preview' button...the data and all of the column names are returned. (Just proving that everything works.)

However I haven't figure out how to set the column names typically set by OLE DB Source component. Right now they are blank. Usually at design time when you reference a table or use simple select statement the OLE DB Source task can map the columns specified by the table name or select statement to create a list of columns that are used for the output and thus by other components in the data flow task.

But when executing a stored procedure...the column names are not returned until completion (i.e. runtime) of the stored procedure. This is the problem.

...cordell...

You're absolutely right. This IS a problem with sprocs. And I agree that this sounds like a good justification for using the Execute SQL Task route. However, I suggest another workaround here:

Using stored procedures inside an OLE DB Source component
(http://blogs.conchango.com/jamiethomson/archive/2006/12/20/SSIS_3A00_-Using-stored-procedures-inside-an-OLE-DB-Source-component.aspx)

that you may wish to employ that will enable you to use the OLE DB Source component.

-Jamie

|||

I found your blog entry on the subject just as I was receiving your email.

The reason why a UDF doesn't work for my solution is the amount of transformation processing that must be performed upon the data. Basically I have 10,000's of data records that are processed and then randomized into a laboratory trial groups which are then distributed out to various computer systems for analysis.

I ended up changing around the stored procedure to create a table in the database...and then once the SSIS work has completed...I drop the table. A less than perfect solution...but it gets the job done and it is time to move on.

Thank you Jamie for your time to answer my questions and your patience.

...cordell...

Saturday, February 25, 2012

Recording Gaps

hi,

I have a view that contains details of when people are allocated to certain task, relevant fields as follows:

RES_ID int(4) (The Id no for that member of staff)
PK TASK_ID int(4) (the code for the task)
PK START_DATE datetime(8) (The date and time that they started on the task
END_DATE datetime(8) (when the task finishes)

I have been asked to create a report that shows when people are NOT working on a particular date (so they can reassign people if a someone calls in sick). Sounds easy until you think about it.

e.g. say Brian works the following hours on 02.01.2007
3.00am - 4.00am
4.30am - 6.00am
7.00am - 11.00am

I need to show the following in report:
Brian free 12.00am - 2.59am
Brian free 4.01am - 4.29am
Brian free 6.01am - 6.59am
Brian free 11.01am - 11.59pm

(I need this info for each member of staff)

I cannot work out how to do this. I am relatively new to SQL server but have a good understanding of relational databases.

Any help would be much appreciated as I am totally stuck.

Thanks,
Chris

The best way to accomplish this type of goal is to have a 'Calendar' table. Then you simply JOIN against the Calendar table to interact with your data in a temporal fashion.

Read about using a Calendar table here:

Datetime -Calendar Table
http://www.aspfaq.com/show.asp?id=2519

|||

Try:

Code Snippet

createtable #t (

RES_ID int,

TASK_ID int,

[START_DATE] datetime,

END_DATE datetime

)

go

insertinto #t values(1, 1,'2007-06-18T03:00:00','2007-06-18T04:00:00')

insertinto #t values(1, 1,'2007-06-18T04:30:00','2007-06-18T06:00:00')

insertinto #t values(1, 1,'2007-06-18T07:00:00','2007-06-18T11:00:00')

insertinto #t values(2, 1,'2007-06-18T03:20:00','2007-06-18T04:30:00')

insertinto #t values(2, 1,'2007-06-18T04:31:00','2007-06-18T06:15:00')

insertinto #t values(2, 1,'2007-06-18T07:00:00','2007-06-18T12:00:00')

go

declare @.d datetime

set @.d ='20070618'

;with cte

as

(

select

a.RES_ID,

dateadd(minute, 1, a.END_DATE)as [START_DATE_1],

dateadd(minute,-1,

(

selectmin(b.[START_DATE])

from #t as b

where b.RES_ID = a.RES_ID and b.[START_DATE] > a.END_DATE

)

)as [END_DATE_1]

from

#t as a

where

a.[START_DATE] >= @.d and a.[END_DATE] <dateadd(day, 1, @.d)

andnotexists(

select*

from #t as b

where

b.RES_ID = a.RES_ID

and b.[START_DATE] >= @.d and b.[END_DATE] <dateadd(day, 1, @.d)

and b.[START_DATE] =dateadd(minute, 1, a.END_DATE)

)

and a.END_DATE <(

selectmax(c.END_DATE)

from #t as c

where

c.RES_ID = a.RES_ID

and c.[START_DATE] >= @.d and c.[END_DATE] < dateadd(day, 1, @.d)

)

)

select

*

from

cte

union

select

RES_ID,

@.d,

dateadd(minute, -1, min([START_DATE]))

from

#t

where

[START_DATE] >= @.d and [END_DATE] < dateadd(day, 1, @.d)

group by

RES_ID

having

dateadd(minute, -1, min([START_DATE])) > @.d

union

select

RES_ID,

dateadd(minute, 1, max([START_DATE])),

dateadd(minute, 1439, @.d)

from

#t

where

[START_DATE] >= @.d and [END_DATE] < dateadd(day, 1, @.d)

group by

RES_ID

having

dateadd(minute, 1, max([START_DATE])) < dateadd(minute, 1439, @.d)

order by

RES_ID,

[START_DATE_1]

go

drop table #t

go

The idea behind this possible solution, is to find the gaps for each RES_ID for a specific date.

AMB

|||

Hi,

thanks for the responses. Hunchback, how would I turn this into a stored procedure with the date as a parameter? I have tried but get lots of syntax errors. I'm sorry but I have only created basic SPs in the past.

Thanks,

Chris

|||

Code Snippet

create procedure dbo.usp_p1

@.d datetime

as

set nocount on

;with cte

as

(

select

a.RES_ID,

dateadd(minute, 1, a.END_DATE)as [START_DATE_1],

dateadd(minute,-1,

(

selectmin(b.[START_DATE])

from #t as b

where b.RES_ID = a.RES_ID and b.[START_DATE] > a.END_DATE

)

)as [END_DATE_1]

from

#t as a

where

a.[START_DATE] >= @.d and a.[END_DATE] <dateadd(day, 1, @.d)

andnotexists(

select*

from #t as b

where

b.RES_ID = a.RES_ID

and b.[START_DATE] >= @.d and b.[END_DATE] <dateadd(day, 1, @.d)

and b.[START_DATE] =dateadd(minute, 1, a.END_DATE)

)

and a.END_DATE <(

selectmax(c.END_DATE)

from #t as c

where

c.RES_ID = a.RES_ID

and c.[START_DATE] >= @.d and c.[END_DATE] < dateadd(day, 1, @.d)

)

)

select

*

from

cte

union

select

RES_ID,

@.d,

dateadd(minute, -1, min([START_DATE]))

from

#t

where

[START_DATE] >= @.d and [END_DATE] < dateadd(day, 1, @.d)

group by

RES_ID

having

dateadd(minute, -1, min([START_DATE])) > @.d

union

select

RES_ID,

dateadd(minute, 1, max([START_DATE])),

dateadd(minute, 1439, @.d)

from

#t

where

[START_DATE] >= @.d and [END_DATE] < dateadd(day, 1, @.d)

group by

RES_ID

having

dateadd(minute, 1, max([START_DATE])) < dateadd(minute, 1439, @.d)

order by

RES_ID,

[START_DATE_1]

go

exec dbo.usp_p1 '19960704'

go

AMB

|||

hi,

I keep getting the following message when I try to save the SP

ADO error:Incorrect syntax near the word 'with'

the server is SQL SERVER 2000 and I am trying to save the SP in an Access .adp file. Do I need a slightly different syntax?

Thanks,

Chris

|||

Commom table expressions were introduced with SS 2005, so we have to change the statement.

create procedure dbo.usp_p1

@.d datetime

as

set nocount on

select

a.RES_ID,

dateadd(minute, 1, a.END_DATE)as [START_DATE_1],

dateadd(minute,-1,

(

selectmin(b.[START_DATE])

from #t as b

where b.RES_ID = a.RES_ID and b.[START_DATE] > a.END_DATE

)

)as [END_DATE_1]

from

#t as a

where

a.[START_DATE] >= @.d and a.[END_DATE] <dateadd(day, 1, @.d)

andnotexists(

select*

from #t as b

where

b.RES_ID = a.RES_ID

and b.[START_DATE] >= @.d and b.[END_DATE] <dateadd(day, 1, @.d)

and b.[START_DATE] =dateadd(minute, 1, a.END_DATE)

)

and a.END_DATE <(

selectmax(c.END_DATE)

from #t as c

where

c.RES_ID = a.RES_ID

and c.[START_DATE] >= @.d and c.[END_DATE] < dateadd(day, 1, @.d)

)

union

select

RES_ID,

@.d,

dateadd(minute, -1, min([START_DATE]))

from

#t

where

[START_DATE] >= @.d and [END_DATE] < dateadd(day, 1, @.d)

group by

RES_ID

having

dateadd(minute, -1, min([START_DATE])) > @.d

union

select

RES_ID,

dateadd(minute, 1, max([START_DATE])),

dateadd(minute, 1439, @.d)

from

#t

where

[START_DATE] >= @.d and [END_DATE] < dateadd(day, 1, @.d)

group by

RES_ID

having

dateadd(minute, 1, max([START_DATE])) < dateadd(minute, 1439, @.d)

order by

RES_ID,

[START_DATE_1]

go

exec dbo.usp_p1 '19960704'

go

|||here's, another approach, this may or may not perform better than hunchbacks post, although they both have the same logic, btw, thanks hunchback for the test data that i piggy back with

[edited]
create table #t (
RES_ID int,
TASK_ID int,
[START_DATE] datetime,
END_DATE datetime
)

insert into #t values(1, 1, '2007-06-18T03:00:00', '2007-06-18T04:00:00')
insert into #t values(1, 1, '2007-06-18T04:30:00', '2007-06-18T06:00:00')
insert into #t values(1, 1, '2007-06-18T07:00:00', '2007-06-18T11:00:00')
insert into #t values(2, 1, '2007-06-18T03:20:00', '2007-06-18T04:30:00')
insert into #t values(2, 1, '2007-06-18T04:31:00', '2007-06-18T06:15:00')
insert into #t values(2, 1, '2007-06-18T07:00:00', '2007-06-18T12:00:00')

declare @.d datetime

set @.d = '20070618'

select *
from #t

select identity(int,1,1) as row
, *
, dateadd(mi,-1,start_date) as free_end
, dateadd(mi,1,end_date) as free_start
into #r
from #t
order by
res_id
, start_date

select res_id
, task_id
, min(dateadd(mi,-1,start_date)) as min_start
, max(dateadd(mi,1,end_date)) as max_end
into #minmax
from #t
group by
res_id
, task_id

select distinct
t.res_id
, t.task_id
, dateadd(mi,1,dateadd(mi,-1,@.d)) as free_start
, r.min_start as free_end
from #t t inner join
#minmax r on t.res_id = r.res_id
and t.task_id = r.task_id
union
select r1.res_id
, r1.task_id
, r1.free_start as free_start
, r2.free_end as free_end
from #r r1 inner join
#r r2 on r1.row = r2.row - 1
and r1.res_id = r2.res_id
and r1.task_id = r2.task_id
union
select distinct
t.res_id
, t.task_id
, r.max_end as free_start
, dateadd(mi,-1,dateadd(day,1,@.d)) as free_end
from #t t inner join
#minmax r on t.res_id = r.res_id
and t.task_id = r.task_id

drop table #t
drop table #r
drop table #minmax|||

hi Hunchback,

thanks very much this is great, but having had a close look at the data that the report has to deal with, it is not quite there - not your fault, mine for not being specific enough.

These are the extra conditions it has to deal with:

a task can start on the day before but end on the day of the report,e.g.

Chris task1 01/01/2007 23:50 - 02/01/2007 01.00

for the above, the report would have to say the freetime started at 01.01am.

Also, tasks can overlap ,e.g.

Chris task1 02/01/2007 06.50 - 02/01/2007 07.30

Chris task2 02/01/2007 07.15 - 02/01/2007 07.40

Chris task4 02/01/2007 07.20 - 02/01/2007 07.35

Chris task3 02/01/2007 07.50 - 02/01/2007 23.59

in the above the freetime is

00.00 - 06.49,

07.41 - 07.49

And finally,

if someone does not have any tasks that day then their freetime should show 00.00 - 23.59.

I realise that these extra conditions make it that much harder, but they were the reason that I originally thought I had no chance of working it out. It is my fault that I overlooked mentioning them.

Thanks,

Chris

|||You will probably find that cursors run much quicker here when you have a realistic amount of data.

How does this code grab you? I'd use a proper resources table in the first statement though. This should handle overlaps and people who are missing.

--First populate everyone
select
r.res_id, @.thedate as start_date, dateadd(day,1,dateadd(minute,-1,@.thedate)) as end_date
into #tmp
from (select distinct res_id from #t) r

--Now run through the time worked
declare csrCsr cursor for
select res_id, start_date, end_date
from #t
where start_date >= @.thedate
and start_date < dateadd(day,1,@.thedate)
order by res_id, start_date
for read only

declare @.res int, @.start datetime, @.end datetime

open csrCsr
fetch csrCsr into @.res, @.start, @.end
while (@.@.fetch_status = 0)
begin
-- For each overlap, put records in either side, and then get rid of the original
insert into #tmp
select @.res, start_date, dateadd(minute,-1,@.start)
from #tmp
where res_id = @.res
and start_date < @.end
and @.start < end_date
and start_date < @.start

insert into #tmp
select @.res, dateadd(minute,1,@.end), end_date
from #tmp
where res_id = @.res
and start_date < @.end
and @.start < end_date
and @.end < end_date

delete
from #tmp
where res_id = @.res
and start_date < @.end
and @.start < end_date

fetch csrCsr into @.res, @.start, @.end
end
close csrCsr
deallocate csrCsr

--Now query the table, and drop the temporary resource
select * from #tmp
drop table #tmp

--Rob|||Oh, throw that into a stored procedure, like this:

create procedure dbo.fetch_times (@.thedate datetime)
as
...

--and of course, use the proper table name instead of #t.|||

hi,

I'd like to thank everyone for their help. After a day or too of navel-gazing, I admitted to myself that my SQL is not that great and resorted to.......CURSORS!

Sorry, but once I did that, it was pretty easy (see below). It is all well and good saying everything should be done with set-base solutions, but I don't have the time or skill for the more extreme examples of these.

anyway, here's my solution:

ALTER PROCEDURE GAP_Report
(
@.d DATETIME
)

AS
SET NOCOUNT ON


DECLARE @.resname VARCHAR(50), @.startdate DATETIME, @.enddate DATETIME, @.rname VARCHAR(50), @.edate DATETIME


SET @.rname = ''

DECLARE @.FreeTime TABLE
(
Res_name VARCHAR(50),
free_start DATETIME,
free_end DATETIME
)

DECLARE cCursor CURSOR FAST_FORWARD
FOR

SELECT
RES_NAME,TASK_START_DATE, TASK_FINISH_DATE
FROM
view_TasksPerUser
WHERE
((DATEDIFF(d,TASK_START_DATE,@.d) = 0) OR (DATEDIFF(d,TASK_FINISH_DATE,@.d) = 0))
ORDER BY
RES_NAME,TASK_START_DATE

OPEN cCursor
FETCH cCursor INTO @.resname, @.startdate, @.enddate

WHILE @.@.Fetch_Status = 0
BEGIN
IF @.rname <> @.resname
BEGIN
IF DATEDIFF(d,@.d,@.startdate) = 0
BEGIN
INSERT INTO @.FreeTime VALUES (@.resname,@.d,DATEADD(s,-1,@.startdate))
END

IF @.rname <> ''
BEGIN
IF DATEDIFF(d,@.d,@.enddate) = 0
BEGIN
INSERT INTO @.FreeTime VALUES (@.rname,DATEADD(s,1,@.edate),DATEADD(s,-1,DATEADD(d,1,@.d)))
END
END
SET @.edate = @.enddate
END
ELSE
BEGIN
IF DATEDIFF(s,@.edate,@.Startdate) > 0
BEGIN

INSERT INTO @.FreeTime VALUES (@.resname,DATEADD(s,1,@.edate), DATEADD(s,-1,@.startdate))
END
END

SET @.rname = @.resname

IF @.enddate > @.edate

SET @.edate = @.enddate

FETCH cCursor INTO @.resname, @.startdate, @.enddate

END


CLOSE cCursor
DEALLOCATE cCURSOR

INSERT INTO
@.FreeTime
SELECT
RES_NAME as res_name,
@.d as Free_start,
DATEADD(s,-1,DATEADD(d,1,@.d)) as Free_end
FROM
(SELECT
DISTINCT RES_NAME
FROM
MSP_RESOURCES
WHERE
RES_NAME <> ''
UNION ALL
SELECT
DISTINCT res_name
FROM
@.Freetime) U
GROUP BY res_name
HAVING COUNT(*) = 1

SELECT
*
FROM
@.Freetime
ORDER BY res_name, free_start, free_end

RETURN 0

thanks again,

Chris