Showing posts with label complex. Show all posts
Showing posts with label complex. Show all posts

Monday, March 26, 2012

I'm Stumped (Complex Joins With and Updates)

My head is spinning trying to figure this one out. Ok. Here is the schema...

--

SET ANSI_NULLS ON

GO

SET QUOTED_IDENTIFIER ON

GO

CREATE TABLE [snmpPoller_HostConfig](

[id] [int] IDENTITY(1,1) NOT NULL,

[friendlyName] [nvarchar](50) NOT NULL,

[hostname] [nvarchar](255) NOT NULL,

[community] [nvarchar](255) NOT NULL,

[version] [int] NOT NULL,

[queryTimeout] [int] NOT NULL,

[isActive] [bit] NOT NULL,

[passedSanityCheck] [bit] NOT NULL CONSTRAINT [DF_snmpPoller_HostConfig_passedSanityCheck] DEFAULT ((0)),

CONSTRAINT [PK_snmpPoller_HostConfig] PRIMARY KEY CLUSTERED

(

[id] ASC

)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]

) ON [PRIMARY]

GO

SET ANSI_NULLS ON

GO

SET QUOTED_IDENTIFIER ON

GO

CREATE TABLE [snmpPoller_TargetConfig](

[id] [int] IDENTITY(1,1) NOT NULL,

[hostId] [int] NOT NULL,

[description] [nvarchar](50) NOT NULL,

[oid] [nvarchar](255) NOT NULL,

[interval] [int] NOT NULL,

[lastPollTimestamp] [datetime] NOT NULL,

[nextPollTime] AS (dateadd(second,[interval],[lastPollTimestamp])),

[isActive] [bit] NOT NULL,

[isPolling] [bit] NOT NULL,

CONSTRAINT [PK_snmpPoller_TargetConfig] PRIMARY KEY CLUSTERED

(

[id] ASC

)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]

) ON [PRIMARY]

GO

ALTER TABLE [dbo].[snmpPoller_TargetConfig] WITH CHECK ADD CONSTRAINT [FK_snmpPoller_TargetConfig_snmpPoller_HostConfig] FOREIGN KEY([hostId])

REFERENCES [snmpPoller_HostConfig] ([id])

Ok. So I have this query

WITH WorkTable ( Tag, Parent, [Host!1!hostId],

[Target!2!targetId], [Host!1!hostname], [Host!1!community],

[Host!1!version], [Host!1!timeout], [Target!2!oid], [Target!2!interval]

)

AS

(

SELECT DISTINCT

1 AS Tag,

NULL AS Parent,

H.id AS [Host!1!hostId],

NULL AS [Target!2!targetId],

hostname AS [Host!1!hostname],

community AS [Host!1!community],

version AS [Host!1!version],

queryTimeout AS [Host!1!timeout],

NULL AS [Target!2!oid],

NULL AS [Target!2!interval]

FROM snmpPoller_HostConfig H, snmpPoller_TargetConfig T

WHERE H.id = T.hostId

AND t.isPolling = 0

AND t.isActive = 1

AND h.isActive = 1

AND t.lastPollTimestamp < { fn NOW() }

AND h.passedSanityCheck = 1

UNION ALL

SELECT DISTINCT

2 AS Tag,

1 AS Parent,

hostId AS [Host!1!hostId],

T.id AS [Target!2!targetId],

NULL AS [Host!1!hostname],

NULL AS [Host!1!community],

NULL AS [Host!1!version],

NULL AS [Host!1!timeout],

oid AS [Target!2!oid],

interval AS [Target!2!interval]

FROM snmpPoller_HostConfig H, snmpPoller_TargetConfig T

WHERE H.id = T.hostId

AND t.isPolling = 0

AND t.isActive = 1

AND h.isActive = 1

AND t.lastPollTimestamp < { fn NOW() }

AND h.passedSanityCheck = 1

)

SELECT * FROM WorkTable

ORDER BY [Host!1!hostId], [Target!2!targetId]

FOR XML EXPLICIT, ROOT ('Hosts')

That generates this xml

<Hosts>

<Host hostId="6" hostname="XXX.XXX.XXX.XXX" community="XXXXX" version="2" timeout="30">

<Target targetId="1757" oid=".1.3.6.1.2.1.31.1.1.1.6." interval="30" />

<Target targetId="1758" oid=".1.3.6.1.2.1.31.1.1.1.10." interval="30" />

<Target targetId="1759" oid=".1.3.6.1.2.1.31.1.1.1.7." interval="30" />

<Target targetId="1760" oid=".1.3.6.1.2.1.31.1.1.1.11." interval="30" />

</Host>

<Host hostId="8" hostname=" XXX.XXX.XXX.XXX " community="XXXXXX" version="2" timeout="30">

<Target targetId="2037" oid=".1.3.6.1.2.1.31.1.1.1.6." interval="30" />

<Target targetId="2038" oid=".1.3.6.1.2.1.31.1.1.1.10." interval="30" />

<Target targetId="2039" oid=".1.3.6.1.2.1.31.1.1.1.7." interval="30" />

<Target targetId="2040" oid=".1.3.6.1.2.1.31.1.1.1.11." interval="30" />

</Host>

</Hosts>

Now the problem is that the xml that I generate is to ‘big’. When I submit a get request to the host, I can only fit 128 OIDs into the request PDU. My query, as it is, returns many hosts with upwards with 1000 targets. So question number 1 is how do return the top 128 targets for each host?

Now here is the real problem. I am replacing a working design in an effort to pick up a scale point. The current design has a dispatcher that will hand off the hostId to a work queue where it is picked up by a ‘thread’. This thread will then execute this sql.

SqlCommand^ command = connection->CreateCommand();

command->Parameters->AddWithValue("@.hostId", hostId);
command->CommandText =

"DECLARE @.resultTable TABLE("+

" targetId int NOT NULL,"+

" hostId int NOT NULL,"+

" oid nvarchar(255) NOT NULL"+

")"+

""+

"UPDATE TOP(128) snmpPoller_TargetConfig"+

" SET isPolling = 1 "+

" OUTPUT INSERTED.id, INSERTED.hostId, INSERTED.oid INTO @.resultTable"+

"WHERE (isPolling = 0) AND (isActive = 1) AND (id = @.hostId) AND (lastPollTimestamp < { fn NOW() })"+

""+

""+

"SELECT * FROM @.resultTable";

SqlDataReader^ reader = command->ExecuteReader();

So rather than make (host * (number of targets / 128)) calls per dispatch cycle, I need to make it all in one call.

So SQL gurus…. What’s the kung-fu? How do I get all my hosts with the top 128 targets AND set a flag on all targets in one atomic shot (I believe this ‘one-shot’ statement can be built off the with(), but I’m nothing but confused at this point)

Paul

Need SQL Advice? http://sqladvice.com
Need RegEx Advice? http://regexadvice.com
Need XML Advice? http://xmladvice.com

is it possible to use ROW_NUM() ranking function within your query and then get the outputs based on row num. Also if you paste your sample data it shall aid the understanding|||

I actually just came up with this. It works just fine, but I'd like to consolidate it down to one statement. Any thoughts?

--

BEGIN TRANSACTION

DECLARE @.buffer TABLE

(

Tag int,

Parent int,

[Host!1!hostId] int,

[Target!2!targetId] int,

[Host!1!hostname] nvarchar(255),

[Host!1!community] nvarchar(255),

[Host!1!version] int,

[Host!1!timeout] int,

[Target!2!oid] nvarchar(255),

[Target!2!interval] int

);

WITH WorkTable ( Tag, Parent, [Host!1!hostId],

[Target!2!targetId], [Host!1!hostname], [Host!1!community],

[Host!1!version], [Host!1!timeout], [Target!2!oid], [Target!2!interval]

)

AS

(

SELECT DISTINCT

1 AS Tag,

NULL AS Parent,

H.id AS [Host!1!hostId],

NULL AS [Target!2!targetId],

hostname AS [Host!1!hostname],

community AS [Host!1!community],

version AS [Host!1!version],

queryTimeout AS [Host!1!timeout],

NULL AS [Target!2!oid],

NULL AS [Target!2!interval]

FROM snmpPoller_HostConfig H, snmpPoller_TargetConfig T

WHERE H.id = T.hostId

AND t.isPolling = 0

AND t.isActive = 1

AND h.isActive = 1

AND t.lastPollTimestamp < { fn NOW() }

AND h.passedSanityCheck = 1

UNION ALL

SELECT DISTINCT

2 AS Tag,

1 AS Parent,

hostId AS [Host!1!hostId],

T.id AS [Target!2!targetId],

NULL AS [Host!1!hostname],

NULL AS [Host!1!community],

NULL AS [Host!1!version],

NULL AS [Host!1!timeout],

oid AS [Target!2!oid],

interval AS [Target!2!interval]

FROM snmpPoller_HostConfig H, snmpPoller_TargetConfig T

WHERE H.id = T.hostId

AND t.isPolling = 0

AND t.isActive = 1

AND h.isActive = 1

AND t.lastPollTimestamp < { fn NOW() }

AND h.passedSanityCheck = 1

AND t.id IN(

SELECT TOP(128) id FROM snmpPoller_TargetConfig

WHERE isPolling = 0 AND isActive = 1 AND lastPollTimestamp < { fn NOW() }

AND hostId = h.id

)

)

INSERT INTO @.buffer

SELECT * FROM WorkTable

UPDATE t SET isPolling = 1

FROM snmpPoller_TargetConfig t,

@.buffer b

WHERE

t.id = b.[Target!2!targetId]

SELECT * FROM @.buffer

ORDER BY [Host!1!hostId], [Target!2!targetId]

FOR XML EXPLICIT, ROOT ('Hosts')

COMMIT TRANSACTION

Sorry, I can't post the data, the schema should be suffecient. Just say there for 100 hosts records and 750 target records per host.

|||

Please take a look at the OUTPUT clause. You can just perform the UPDATE statement and get the relevant columns (even expressions) from the inserted/deleted tables into a table variable for example. You can then do the SELECT against the table variable. Please take a look at my blog post below for one such example:

http://blogs.msdn.com/sqltips/archive/2005/06/13/OUTPUT_clause.aspx

Wednesday, March 7, 2012

I need some help with a complex query

I've written a lot of queries in the past, but I'm having a lot of trouble with this one.

I have 3 tables: Thread, Reply, User

Thread has these relevant fields: ThreadID, UserID, DTStamp, Subject

Reply has these relevant fields: ThreadID, UserID, DTStamp

User has these relavent fields: UserID, Name

A few details:
- Thread and Reply connect with ThreadID
- Thread and Reply both connect to Person with UserID
- Thread and Reply share a 1 to many relationship (1 Thread with many Replies)
- It is also possible there are no replies

What I need is a query that looks at thedata and returns a set of records with the following data fields:

Subject: The Subject of the thread
CreationDate: The Date that Subject thread was created
Author: The Name of the UserID that created that thread
Replies: The Number of Replies to the Subject thread
LastPost: The Date of the Last Reply
LastPostAuthor: The Name of the UserID of the Last Reply

And I need this all sorted by Date of Last Reply

Is this even doable? Are there any suggestions on the best way to get started?


Thanks in advance,

Chris

Hi Chris my friend, I will help you on this.

First run the following SQL to create a function: -

CREATE FUNCTION fn_GetLastPostUserNameByThreadID
(
@.ThreadID AS INT
)

RETURNS varchar(30)

AS

BEGIN

DECLARE @.Author AS VARCHAR(30)

SET @.Author = (
SELECT Name FROM User WHERE UserID =
(SELECT TOP 1 USERID FROM Reply WHERE ThreadID = @.ThreadID
ORDER BY dtstamp DESC)
)

RETURN @.Author

END

Now for the SQL to get you the results: -

SELECT thread.Subject,
thread.dtstamp,
user.name,
COUNT(reply.threadid) AS Replies,
MAX(reply.dtstamp) AS LastPost,
dbo.fn_GetLastPostUserNameByThreadID(thread.threadid) AS LastPostAuthor

FROM thread

INNER JOIN user on thread.userid = user.userid
LEFT OUTER JOIN reply ON thread.threadid = reply.threadid

GROUP BY Subject,
thread.dtstamp,
user.name,
dbo.fn_GetLastPostUserNameByThreadID(thread.threadid)

ORDER BY reply.dtstamp DESC

|||

Thank you so much! I can't wait to try this out.

I have created stored procedures before, but not functions, so I have a couple follow-up questions.

When I look at my database through SQL Server Management Studio Express, I see funtions and under that 4 categories:

Table-valued Functions|||

Hi Chris,

A Table-valued function returns a table. To use one, you do "SELECT * FROM dbo.MyFunction()". The following example takes a string and turns it into a table.

create FUNCTION dbo.StringArrayIntoTable
(
@.String VARCHAR(8000),
@.Separator VARCHAR(1)
)
RETURNS @.tblStrings TABLE(Item VARCHAR(8000))

AS

BEGIN

DECLARE @.pos INT,
@.SubStr VARCHAR(10)


SET @.pos = CHARINDEX(@.Separator, @.String)

WHILE @.pos > 0
BEGIN
SET @.SubStr = SUBSTRING(@.String, 0, @.pos)

INSERT INTO @.tblStrings (Item) VALUES (@.SubStr)

SET @.String = SUBSTRING(@.String, LEN(@.SubStr) + 2, LEN(@.String) - LEN(@.SubStr) + 1)
SET @.pos = CHARINDEX(@.Separator, @.String)
END

INSERT INTO @.tblStrings (Item) VALUES (@.String)
RETURN
END

The first parameter is the string. The second is the separator. Test it with the following: -

select * from dbo.StringArrayIntoTable('red,blue,yellow', ',')
select * from dbo.StringArrayIntoTable('USA|Germany|Russia|UK', '|')

This is useful if you need to pass an array of values into a stored procedure. Just pass in a string that you can separate!

Scalar valued functions only return one value and when using them, you don't use "SELECT * FROM", just "SELECT FunctionName()". You would create one of these if you wanted a function that only returned one value, like the one I gave to you that returns 1 varchar; the author's name.

Aggregate functions are built-in scalar valued functions. For example, SUM and AVG; select SUM(SaleValue) AS Total, AVG(SaleValue) AS AverageSale FROM tblSales.

As for System functions, some are more useful than others. For example, if you want to return 0 for SaleValue if the field value is null, you can use SELECT IsNull(SaleValue, 0) AS SaleValue. It returns whatever the SalesValue is, but 0 if it is NULL.

As for your second question, always use a stored procedure. When a stored procedure cannot give you directly what you need without calling a function, as in the problem you posted, have the procedure call a function. Stored procedures have pre-compiled execution plans and execute more efficiently. On the other hand, performance hits are associated with functions so use them only when necessary.

By the way. I noticed that within the SQL I gave to you I used "user" to refer to the author table. This cannot be right because user is not a valid table name. I did not realize this at first because I did it in Notepad. Please substitute this with the correct table name and the SQL should work.

In return for all of this help, I only ask that you mark me as the answerer of your question in this forum.

Kind regards

Scotty

|||

Scotty,

Wow! I can't begin to thank you enough for your help. Your code and explanations are just what I needed.

FYI, my table is called User. I probably should change the name, but for now I just refer to it like this [User] and it works okay.

Also, I made one other change to the code, I changed the last line to "Order By LastPost Desc" as it had a problem with "reply.dtstamp" not being part of the result set.

Thanks again,

Chris

p.s. If you want to see your code in action, feel free to check out my site MoviePoet.com early next week.

Sunday, February 19, 2012

I need help with an insert clause, please help

I am trying to write a complex insert statement and not really sure how to get started.

First I am building an application to a record label to add artist, songs, pictures, video, and music to their site.

Thanks to asp.net 2.0 building the application interface was easy, but now I realize I have run into a brick wall and need some help.

in one application, called "add artist album"

in this application, you, the website administrator, are adding information to two different tables (artist (holds all info about the artist), album (holds all the info about artist album))

I have no clue how to really start writing an insert statement for this.

Basically I want to be able to insert the album data (artistid (foreign key), album name and release date) and also have a drop down listbox, which is connected to the database by the sqldatasource connector to allow the administrator to choose an artist from the artist table so that when they add the albem and release date they, the administrator, can choose which artist in the drop down list box to associate with the album and release date data that goes in the album table. That association is made with the artistid because it is a foreign key to the artist table but how do I insert the chosen artistid number into that foreign key field for the album table?


Please can someone point me in the right direction.

I am thinking that the insert statement will be something like and insert with nested select statement and inner join included but i haven't a clue how to do this.

My table DDL

Create table artist (artistid int prmrykey, artistname varchar (100), bio varchar(100))

Create table album (albumid int prmrykey, albumname varchar (100), releasedate date, artistid int foreignkey)

My DML for the insert statement so far:

ALTER PROCEDURE sp_AddArtistAlbum
@.AlbumName varchar(50),
@.ReleasedDate datetime,
@.ArtistID int
AS

SET NOCOUNT ON

DECLARE@.AlbumIDINTINSERT INTOtb_Album

(AlbumName, ReleasedDate, ArtistID)

VALUES(@.AlbumName, @.ReleasedDate,selectArtistIDfromtb_ArtistwhereArtistID = (ArtistID from sqldatasource from the drop down listbox) )

Like I said know I am supposed to have a select subquery statement that is nested to really make this thing work but I do not know where to start, can someone please help me.

I hope I have provided enough information.

My expected results are to insert data from into the album table and have that data associated with an artist chosen in the drop down box.

Please Help!!!!!!!!!!!!!!

ALTER PROCEDUREsp_AddArtistAlbum@.AlbumNamevarchar(50),@.ReleasedDatedatetime,@.ArtistIDintASSET NOCOUNT ONDECLARE @.AlbumIDINTINSERT INTO tb_Album(AlbumName, ReleasedDate, ArtistID)VALUES (@.AlbumName, @.ReleasedDate, @.ArtistID)

The ArtistID is the SelectedValue from your DropDownList (althought the Artist Name appears in the dropdown). That's all you need to insert. It's there and available without any additional messing about.

If you look at the logic of your proposed SQL, you will see that it says "I have the ArtistID from the dropdown, Now I want to select the ArtistID from the Artist table that matches the ID I already have". Bit of a nonsense when you analyse it like that...Big Smile

I need help please

Hello,
I started yesterday working with reporting services to get done some complex reports but I've encountered a lot troubles.
For example, I created one report and set both with and height for the body, then added one rectangle and inside of it, I dragged a Chart. Till then everything looked fine, but when I viewed the preview, my report is four page lenth and the charts appears on page 4 !!!
I've read in the newsgroups something about checking the vale of the Report.PageWith against the Body.Width, but WHERE CAN I FIND THE REPORT.PAGEWITDH ? is it withing the VS IDE '
Also, how can I add a "horizontal total" in a matrix '
I have the following layout for a matrix:
-- State (columns )
Month (rows) ... Units sold
My dataset returns these three fields
and I want something like ...
-- State (columns ) , Total Units
Month (rows) ... Units sold ...... , total units sold by month
My task is to create several reporting and each one will have several charts, lists and matrix.
Thanks
CesarSelect "Report" in the property browser. There would be PageSize property in
Layout category
Quoting from Books Online (
ms-help://MS.RSBOL80.1033/RSCREATE/htm/rcr_creating_structure_objects_v1_7vi
0.htm )
To add a subtotal to a matrix, add a subtotal to an individual group within
the matrix. Groups do not have subtotals by default. To add a subtotal to a
group, right-click the group column or row header and then click Subtotal.
This will open a new header for the subtotal. Reporting Services will
calculate the subtotal based on the aggregate in the data cell for the
group.
--
This posting is provided "AS IS" with no warranties, and confers no rights.
"Cesar" <Cesar@.discussions.microsoft.com> wrote in message
news:DFB067AA-2DB6-4CEF-AC54-0C349FDE0E81@.microsoft.com...
> Hello,
> I started yesterday working with reporting services to get done some
complex reports but I've encountered a lot troubles.
> For example, I created one report and set both with and height for the
body, then added one rectangle and inside of it, I dragged a Chart. Till
then everything looked fine, but when I viewed the preview, my report is
four page lenth and the charts appears on page 4 !!!
> I've read in the newsgroups something about checking the vale of the
Report.PageWith against the Body.Width, but WHERE CAN I FIND THE
REPORT.PAGEWITDH ? is it withing the VS IDE '
> Also, how can I add a "horizontal total" in a matrix '
> I have the following layout for a matrix:
> -- State (columns )
> Month (rows) ... Units sold
> My dataset returns these three fields
> and I want something like ...
> -- State (columns ) , Total Units
> Month (rows) ... Units sold ...... , total units sold by month
> My task is to create several reporting and each one will have several
charts, lists and matrix.
> Thanks
> Cesar