Showing posts with label int. Show all posts
Showing posts with label int. Show all posts

Friday, March 30, 2012

Return dataset in one column

Hi there

I have the following two tables

mainprofile (profile varchar(20), description)
accprofile (profile varchar(20), acct_type int)

Sample data could be

mainprofile
------
prof1 | profile one
prof2 | profile two
prof3 | profile three

accprofile
-----

prof1 | 0
prof1 | 1
prof1 | 2
prof2 | 0

Now doing a join between these two tables would return multiple rows,
but I would like to know whether it would be possible to return
acct_type horizontally in a column of the result set, e.g.

prof1 | profile one | [0,1,2]
prof2 | profile two | [0]

I could probably manage this with cursors, but it would be very
resource intensive. Is there a better way?

Regards,
LouisFor a one time data display or if this is used by a single application or a
report, you should consider retrieving the resultset to the client side,
leverage the display/presentation language's string manipulative features
and appropriately format the data there.

If this is more of a general requirement and used by several applications,
in certain cases it may make some sense to do it at the server using t-SQL.
For some options see: http://www.projectdmx.com/tsql/rowconcatenate.aspx
--
Anith|||

Quote:

Originally Posted by

For some options see: http://www.projectdmx.com/tsql/rowconcatenate.aspx


Thanks. In the end I decided to stick with using a CURSOR

Regards,
Louis

Wednesday, March 28, 2012

Return a value after insert the query

Hi!


create table testReturn
(
id int identity(100,1),
name varchar(10)
)

How can I return the value of identity column after inserting the value.

Dim objConn As SqlConnection
Dim SQLCmd As SqlClient.SqlCommand
Dim ds As New DataSet
Dim strsql As String

Try

objConn = New SqlConnection
objConn.ConnectionString = _
"Network Library=DBMSSOCN;" & _
"Data Source=localhost;" & _
"Initial Catalog=mydb;" & _
"User ID=userid;" & _
"Password=pass"

objConn.Open()

strsql = "insert into testReturn values ('a')"
SQLCmd = New SqlClient.SqlCommand(strsql, objConn)
Dim rowsAffected As Integer = 0
rowsAffected = SQLCmd.ExecuteNonQuery

Dim rv As String
rv = SQLCmd.Parameters(0).Value.ToString()
Response.Write(rv)


Catch ex As Exception
Response.Write(ex.ToString)
End Try


SeeHow do I get the IDENTITY / AUTONUMBER value for the row I inserted?

|||

strsql = "insert into testReturn values ('a'); select @.@.Identity"
SQLCmd = New SqlClient.SqlCommand(strsql, objConn)

dim Identiy as Object

Identity = SQLCmd.ExecuteScalar

|||

You need to put "Select @.@.identity" statement immediately after your insert query so it would return the ID value of the record inserted, using the preceding Insert statement.

Cheers
Ritesh

|||

Using @.@.IDENTITY is an vulnerable approach, since it returns the last inserted id of any table. If you are using SQL 2005 then you can use the OUTPUT clause.

SeeHow to get an Identity value with SQL Server 2005

|||

You can either use @.@.identity or scope_identity().

@.@.identity gives you the last generated identity value.

scope_identity() gives you the last generated identity value for current scope.

Just have a quick look at BOL for further understanding.

Hope this will help.

Return a resultset from a Stored Pro

Hello all,
I want to be able to be able to return a resultset from a Stored Procedure.

Something like :

CREATE PROCEDURE LSNOnAJob
@.MyJobNo AS INT,@.MyLsn VarChar(10) OUTPUT

AS

SELECT @.MyLsn = dbo.TSample.ISmpShortCode
FROM dbo.TJob INNER JOIN
dbo.TSample ON dbo.TJob.IJobN = dbo.TSample.IJobN
WHERE (dbo.TJob.IJobN = @.MyJobNo)
GO

I pass the IJobN into the Sproc and it should give me a resultset back that contains 5 Ismpshortcode's (which is the resultset I want to pass back to Access XP). But the value that gets returned is the last result from the recordset.

I'm obviously doing something a bit stupid, so any help would be greatly appreicitated.would this work for you or do you need the results returned in an output variable?

CREATE PROCEDURE LSNOnAJob
@.MyJobNo AS INT
--,@.MyLsn VarChar(10) OUTPUT

AS

SELECT dbo.TSample.ISmpShortCode
FROM dbo.TJob INNER JOIN
dbo.TSample ON dbo.TJob.IJobN = dbo.TSample.IJobN
WHERE dbo.TJob.IJobN = @.MyJobNo
GO|||I need the results returned back to an Access DB|||Just use a pass through query and EXEC the sproc...

Wednesday, March 21, 2012

retrieving selected join records

Hi,
I have the folowing 3 (SS2005) tables:

CREATE TABLE [dbo].[tblSubscription](
[SubscriptionID] [int] IDENTITY(1000000,1) NOT NULL,
[SubscriberID] [int] NOT NULL,
[Status] [int] NOT NULL,
[JournalID] [int] NOT NULL,

CREATE TABLE [dbo].[tblTransaction](
[TransactionID] [bigint] IDENTITY(100000000,1) NOT NULL,
[TransactionTypeID] [int] NOT NULL,
[SubscriptionID] [int] NOT NULL,
[Created] [datetime] NOT NULL,

CREATE TABLE [dbo].[tblMailing](
[MialingID] [bigint] IDENTITY(1000000000,1) NOT NULL,
[SubscriptionID] [int] NOT NULL,
[MailTypeID] [int] NOT NULL,
[MailDate] [datetime] NOT NULL

So for each subscription there can be 1 or more transactions and 0 or
more mailings, and the mailings are not necassarily related to the
transactions. What I am having difficulty doing is this:

I wish to select tblMailing.MailingID, tblMailing.MailDate,
tblMailing.SubscriptionID (or tblSubscription.SubscriptionID),
tblSubscription.SubscriberID, tblSubscription.Status,
tblTransaction.TransactionID, tblTransaction.Created, but I only wish
to retrieve rows from the transaction table where
tblTransaction.Created is the latest dated transaction for that
subscription.
I.E. (maybe this makes more sense..:) I wish to select all rows from
tblMailing along with each mailing's relevent subscription details,
including details of the LATEST TRANSACTION for each of those
subscriptions.

I am currently working along the lines of MAX(tblTransaction.Created)
and possibly GROUP BY in a subquery, but cannot quite figure out the
logic.

Any help appreciated.

Thanks, KoG

King:

Are you wanting the subscription record to appear in the report even if there are as of yet no mailings? That is, do I need to use an outer join or an inner join? I am for the moment assuming that you want the inner join.


Dave

|||

set nocount on
declare @.tblSubscription table
( subscriptionID integer not null,
subscriberID integer not null,
status integer not null,
journalID integer not null,
primary key (subscriptionID)
)

declare @.tblTransaction table
( transactionID integer not null,
transactionTypeId integer not null,
subscriptionID integer not null,
created datetime not null
primary key (transactionID),
unique (subscriptionID, transactionID)
)

declare @.tblMailing table
( mailingId bigint not null,
subscriptionID integer not null,
mailTypeId integer not null,
mailDate datetime not null,
primary key (mailingID),
unique (subscriptionId, mailingId)
)

insert into @.tblSubscription values (1000001, 1000001, 1, 1)
insert into @.tblSubscription values (1000002, 1000002, 1, 1)
insert into @.tblSubscription values (1000003, 1000001, 2, 1)
--select * from @.tblSubscription

insert into @.tblTransaction values (1000001, 1, 1000001, '3/15/6' )
insert into @.tblTransaction values (1000002, 2, 1000001, '4/7/6' )
insert into @.tblTransaction values (1000003, 1, 1000002, '4/3/6' )
insert into @.tblTransaction values (1000004, 1, 1000003, '5/8/6' )
insert into @.tblTransaction values (1000005, 2, 1000003, '10/14/6')
insert into @.tblTransaction values (1000006, 4, 1000003, '9/1/6' )
--select * from @.tblTransaction

insert into @.tblMailing values (1000001, 1000001, 1, '3/15/6' )
insert into @.tblMailing values (1000002, 1000001, 2, '4/4/6' )
insert into @.tblMailing values (1000003, 1000003, 1, '5/9/6' )
insert into @.tblMailing values (1000004, 1000003, 3, '9/3/6' )
--select * from @.tblMailing

--set statistics io on
select m.mailingId,
m.MailDate,
s.subscriptionId,
s.subscriberId,
s.Status,
t.TransactionId,
t.created
from @.tblSubscription s
inner join @.tblMailing m
on s.subscriptionId = m.subscriptionId
inner join
( select q.subscriptionId,
q.transactionId,
row_number () over
( partition by q.subscriptionId
order by q.created desc, q.transactionId desc
) as Seq,
created
from @.tblTransaction q
) t
on t.subscriptionId = s.subscriptionId
and seq = 1
--set statistics io off


-- -- Sample Output: -

-- mailingId MailDate subscriptionId subscriberId Status TransactionId created
-- -- -- -- -- - --
-- 1000001 2006-03-15 00:00:00.000 1000001 1000001 1 1000002 2006-04-07 00:00:00.000
-- 1000002 2006-04-04 00:00:00.000 1000001 1000001 1 1000002 2006-04-07 00:00:00.000
-- 1000003 2006-05-09 00:00:00.000 1000003 1000001 2 1000005 2006-10-14 00:00:00.000
-- 1000004 2006-09-03 00:00:00.000 1000003 1000001 2 1000005 2006-10-14 00:00:00.000

|||Hi Dave,

I only wish to select subscription rows where there is a mailing associated with the subscription. In fact, the driver of the query should be the mailings table, so for each row in tblMailing get the relevent subscription (& latest transaction) data. That means there may be several rows where the data in the subscription-related columns (& hence transaction related ones too) are the same, as a subscription may have several mailings.

I assume that means the inner join is required..

Thanks, Nick
sql

Retrieving rows with 2 indexes

I have a table that contains 2 keys (iId and iVersion) and some other data:

iId int(4) NOT NULL default '0',
iVersion int(4) NOT NULL default '0',
vchName varchar(50) default NULL

The data looks a little like this:

1|1|Fred
1|2|Fred edited once
1|3|Fred edited twice
2|1|Dave
2|2|Dave edited once
2|3|Dave edited twice

I need a sql statement that will return all columns of the latest row (based on the greatest iVersion value) for each unique iId in the table.

So using the data above it should return

1|3|Fred edited twice
2|3|Dave edited twice

Any help would be appreciated!select iId,
iVersion,
vchName
from <table_name>
group by iId
having iVersion = max(iVersion)|||Try:
select iId,
iVersion,
vchName
from <table_name>
where (iId, iVersion) in
( select iId,
max(iVersion) maxVer
from <table_name>
group by iId
);
Or if using Oracle you could use the analytic functions.|||I would suggest using:SELECT *
FROM myTable AS a
WHERE a.iVersion = (SELECT Max(b.iVersion)
FROM myTable AS b
WHERE b.iId = a.iId)-PatP|||May have been that i was using MySQL but none of the above worked!

They did however help me to get some sql that does work...

select iId, vchName, MAX(iVersion) as iVersion
from <Table>
GROUP BY iId

Thanks.|||select iId, vchName, MAX(iVersion) as iVersion
from <Table>
GROUP BY iIdyou may think this works, but it doesn't

even the mysql docs tell you that this gives unpredictable results (holler if you need the link to the page in the docs where it explains this)

what you want is the vchName that comes from the row which has the largest iVersion, but this is not what you are getting, and if it looks like you are getting it, it is a fluke

you could just as easily get this instead --

1|3|Fred edited once
2|3|Dave

i'm sorry if this sounds like i'm dumping all over you, it's not your fault, it's mysql's fault for allowing non-standard sql to run (in any other database system, your query would generate a syntax error)

here's what you want, done without subqueries if you're not on 4.1 yet --
select X.iId
, X.iVersion
, X.vchName
from yourtable as X
inner
join yourtable as Y
on X.iId
= Y.iId
group
by X.iId
, X.iVersion
, X.vchName
having X.iVersion
= max(Y.iVersion)

Retrieving PDF from MS Sql Database using C#

I am now retrieving the PDF from the database and I am getting an error:

Error 1 'GetImages.GetImage(int)': not all code paths return a value

I have:

int imageid =Convert.ToInt32(Request.QueryString["ACTUAL_IMAGE_PDF"]);

And...

privateSqlDataReader GetImage(int imageid)

{

Sql Statement...

}

Could someone help please??

Can you post the complete code?

|||protectedvoid Page_Load(object sender,EventArgs e)

{

int imageid =Convert.ToInt32(Request.QueryString["ACTUAL_IMAGE_PDF"]);SqlDataReader imageContent = GetImage(imageid);

imageContent.Read();

Response.ContentType = imageContent["ImageType"].ToString();

Response.OutputStream.Write((byte[])imageContent["ImageFile"], 0, System.Convert.ToInt32(imageContent["ImageSize"]));

Response.End();

}

privateSqlDataReader GetImage(int imageid)

{

SqlConnection myConnection =newSqlConnection("Data Source=*********");SqlCommand myCommand =newSqlCommand("Select * From DBO.RIMS_TEST_TABLE Where imageid=@.ImagePDF_Name", myConnection);

SqlParameter imageIDParameter =newSqlParameter("@.ImageId",SqlDbType.Int);

imageIDParameter.Value = imageid;

myCommand.Parameters.Add(imageIDParameter);

myConnection.Open();

}

}

|||

Instead ofprivateSqlDataReader GetImage(int imageid)

make it

private void GetImage(int imageid)

since you are not returning anything!

Retrieving Mutiple rows

I have a table like this.

Depositors Table

Value(int) StartDate(Date) AccountID(int)

I want to create a report from this table. the report should look like this.

Value No of Accounts Average Value

For Yesterday

For Last 7days

For Last 30 days

Please Can anyone write a simple query for this?

Thanks

declare @.temptable table (amount decimal(10,2) , duration nvarchar(50),date datetime)

insert into @.temptable(amount,duration,date)

select top 100 sum(grandtotal),

case when saledate = dateadd("d",-1,dateadd("month",0,'07/20/2007')) then 'yesterday' --cast (saledate as nvarchar(30))

when saledate < dateadd("d",-1,dateadd("month",0,'07/20/2007')) and saledate >= dateadd("d",-7,dateadd("month",-1,'07/20/2007')) then 'Last 7 days'

when saledate < dateadd("day",-1,dateadd("month",-1,'07/20/2007')) and saledate >= dateadd("day",-2,dateadd("month",-3,'07/20/2007')) then 'Last month'

when saledate < dateadd("day",-2,dateadd("month",-3,'07/20/2007')) and saledate >= dateadd("d",-1,dateadd("year",-2,'07/20/2007')) then 'Last 1 year'

else '...'

end , saledate

from sale group by saledate order by saledate desc

select sum(amount), duration from @.temptable group by duration order by max(date) desc

Bad formatting but query works..

I checked it..

in my database i have old date so i need to use old date.. but you can use today's date..

|||

Thanks..

I tried with this one..But I did not get what I want.

I changed it lil bit.

declare @.temptable table (amount decimal(10,2) , duration nvarchar(50),date datetime)

insert into @.temptable(amount,duration,date)

select sum(Amount),

case when startdate >= GETDATE()-1 then 'yesterday'

when Startdate >= GETDATE()-7 then 'Last 7 days'

when startdate >=GETDATE()-30 then 'Last month'


end , startdate

from CD group by startdate order by startdate desc


select sum(Amount), duration from @.temptable group by duration order by max(date) desc

Query works. But it does not show values for duration. As example, it does not show whether its yesterday , Last7days or etc.

But I want to get the report as shown above.....

|||

shamen wrote:

Thanks..

I tried with this one..But I did not get what I want.

I changed it lil bit.

declare @.temptable table (amount decimal(10,2) , duration nvarchar(50),date datetime)

insert into @.temptable(amount,duration,date)

select sum(Amount),

case when startdate >= GETDATE()-1 then 'yesterday'

when Startdate >= GETDATE()-7 then 'Last 7 days'

when startdate >=GETDATE()-30 then 'Last month'


end , startdate

from CD group by startdate order by startdate desc


select sum(Amount), duration from @.temptable group by duration order by max(date) desc

Query works. But it does not show values for duration. As example, it does not show whether its yesterday , Last7days or etc.

But I want to get the report as shown above.....

declare @.temptable table (amount decimal(10,2) , duration nvarchar(50),date datetime)

insert into @.temptable(amount,duration,date)

select sum(Amount),

case when startdate = dateadd("d",-1,GETDATE()) then 'yesterday'

when Startdate between dateadd("d",-1,GETDATE()) and dateadd("d",-7,GETDATE()) then 'Last 7 days'

when startdate between dateadd("d",-7,GETDATE()) and dateadd("d",-30,GETDATE()) then 'Last month'

Else 'ABC'
end as duration, startdate

from CD group by startdate order by startdate desc


select sum(Amount), duration from @.temptable group by duration order by max(date) desc

May it works now. For testing purpose always keep default value so atlease you can know that condition is going where

Retrieving Mutiple rows

I have a table like this.

Depositors Table

Value(int) StartDate(Date) AccountID(int)

I want to create a report from this table. the report should look like this.

Value No of Accounts Average Value

For Yesterday

For Last 7days

For Last 30 days

Please Can anyone write a simple query for this?

Thanks

declare @.temptable table (amount decimal(10,2) , duration nvarchar(50),date datetime)

insert into @.temptable(amount,duration,date)

select top 100 sum(grandtotal),

case when saledate = dateadd("d",-1,dateadd("month",0,'07/20/2007')) then 'yesterday' --cast (saledate as nvarchar(30))

when saledate < dateadd("d",-1,dateadd("month",0,'07/20/2007')) and saledate >= dateadd("d",-7,dateadd("month",-1,'07/20/2007')) then 'Last 7 days'

when saledate < dateadd("day",-1,dateadd("month",-1,'07/20/2007')) and saledate >= dateadd("day",-2,dateadd("month",-3,'07/20/2007')) then 'Last month'

when saledate < dateadd("day",-2,dateadd("month",-3,'07/20/2007')) and saledate >= dateadd("d",-1,dateadd("year",-2,'07/20/2007')) then 'Last 1 year'

else '...'

end , saledate

from sale group by saledate order by saledate desc

select sum(amount), duration from @.temptable group by duration order by max(date) desc

Bad formatting but query works..

I checked it..

in my database i have old date so i need to use old date.. but you can use today's date..

|||

Thanks..

I tried with this one..But I did not get what I want.

I changed it lil bit.

declare @.temptable table (amount decimal(10,2) , duration nvarchar(50),date datetime)

insert into @.temptable(amount,duration,date)

select sum(Amount),

case when startdate >= GETDATE()-1 then 'yesterday'

when Startdate >= GETDATE()-7 then 'Last 7 days'

when startdate >=GETDATE()-30 then 'Last month'


end , startdate

from CD group by startdate order by startdate desc


select sum(Amount), duration from @.temptable group by duration order by max(date) desc

Query works. But it does not show values for duration. As example, it does not show whether its yesterday , Last7days or etc.

But I want to get the report as shown above.....

|||

shamen wrote:

Thanks..

I tried with this one..But I did not get what I want.

I changed it lil bit.

declare @.temptable table (amount decimal(10,2) , duration nvarchar(50),date datetime)

insert into @.temptable(amount,duration,date)

select sum(Amount),

case when startdate >= GETDATE()-1 then 'yesterday'

when Startdate >= GETDATE()-7 then 'Last 7 days'

when startdate >=GETDATE()-30 then 'Last month'


end , startdate

from CD group by startdate order by startdate desc


select sum(Amount), duration from @.temptable group by duration order by max(date) desc

Query works. But it does not show values for duration. As example, it does not show whether its yesterday , Last7days or etc.

But I want to get the report as shown above.....

declare @.temptable table (amount decimal(10,2) , duration nvarchar(50),date datetime)

insert into @.temptable(amount,duration,date)

select sum(Amount),

case when startdate = dateadd("d",-1,GETDATE()) then 'yesterday'

when Startdate between dateadd("d",-1,GETDATE()) and dateadd("d",-7,GETDATE()) then 'Last 7 days'

when startdate between dateadd("d",-7,GETDATE()) and dateadd("d",-30,GETDATE()) then 'Last month'

Else 'ABC'
end as duration, startdate

from CD group by startdate order by startdate desc


select sum(Amount), duration from @.temptable group by duration order by max(date) desc

May it works now. For testing purpose always keep default value so atlease you can know that condition is going where

Tuesday, March 20, 2012

Retrieving Hierarchical Data from a single table

I would like to retrieve a hierarchical list of Product Categories from a single table where the primary key is a ProductCategoryId (int) and there is an index on a ParentProductCategoryId (int) field. In other words, I have a self-referencing table. Categories at the top level of the hierarchy have a ParentProductCategoryId of zero (0). I would like to display the list in a TreeView or similar hierarchical data display control.

Is there a way to retrieve the rows in hierarchical order, sorted by CategoryName within level? I would like to do so from a stored procedure.
Example data:

ProductCategoryID CategoryDescription ParentProductcategoryID ParentCategoryDescription Level
-------------------------------------------
1 Custom Furniture 0 0
2 Boxes 0 0
3 Toys 0 0
4 Bedroom 1 Custom Furniture 1
5 Dining 1 Custom Furniture 1
6 Accessories 1 Custom Furniture 1
7 Picture Frames 6 Accessories 2
8 Serving Trays 6 Accessories 2
9 Entertainment 1 Custom Furniture 1
10 Planes 3 Toys 1
11 Trains 3 Toys 1
12 Boats 3 Toys 1
13 Automobiles 3 Toys 1
14 Jewelry 2 Boxes 1
15 Keepsake 2 Boxes 1
16 Specialty 2 Boxes 1

Desired output:

Custom Furniture
Accessories
Picture Frames
Serving Trays
Bedroom
Dining
Entertainment
Boxes
Jewelry
Keepsake
Specialty
Toys
Automobiles
Boats
Planes
Trains

Hello, if I get you right, here is a very short article that might get you started:http://www.mmkit.com/article.php?sid=345&lang=en_GB

HTH. -LV

|||The answer very much depends on whether you are using Sql Server 2005 or an older version. Assuming 2005 then have a read ofHeirarchical Queries in Sql Server 2005.|||Thanks much. This was exactly what I needed. I don't think I could have come up with this solution on my on at this point.|||

--Copy the code to run on your machine. I named your table as TreeSource with columns needed.

IF(SELECTOBJECT_ID('TreeSource','U'))ISNOTNULL

BEGIN

DROPTABLE TreeSource

END

GO

CREATETABLE [dbo].[TreeSource](

[ProductCategoryID] [int]NULL,

[CatDescription] [nvarchar](255)COLLATE SQL_Latin1_General_CP1_CI_ASNULL,

[ParentProductCategoryID] [int]NULL

)ON [PRIMARY]

INSERTINTO [TreeSource]([ProductCategoryID],[CatDescription],[ParentProductCategoryID])VALUES(1,'Custom Furniture',NULL)

INSERTINTO [TreeSource]([ProductCategoryID],[CatDescription],[ParentProductCategoryID])VALUES(2,'Boxes',NULL)

INSERTINTO [TreeSource]([ProductCategoryID],[CatDescription],[ParentProductCategoryID])VALUES(3,'Toys',NULL)

INSERTINTO [TreeSource]([ProductCategoryID],[CatDescription],[ParentProductCategoryID])VALUES(4,'Bedroom',1)

INSERTINTO [TreeSource]([ProductCategoryID],[CatDescription],[ParentProductCategoryID])VALUES(5,'Dining',1)

INSERTINTO [TreeSource]([ProductCategoryID],[CatDescription],[ParentProductCategoryID])VALUES(6,'Accessories',1)

INSERTINTO [TreeSource]([ProductCategoryID],[CatDescription],[ParentProductCategoryID])VALUES(7,'Picture Frames',6)

INSERTINTO [TreeSource]([ProductCategoryID],[CatDescription],[ParentProductCategoryID])VALUES(8,'Serving Trays',6)

INSERTINTO [TreeSource]([ProductCategoryID],[CatDescription],[ParentProductCategoryID])VALUES(9,'Entertainment',1)

INSERTINTO [TreeSource]([ProductCategoryID],[CatDescription],[ParentProductCategoryID])VALUES(10,'Planes',3)

INSERTINTO [TreeSource]([ProductCategoryID],[CatDescription],[ParentProductCategoryID])VALUES(11,'Trains',3)

INSERTINTO [TreeSource]([ProductCategoryID],[CatDescription],[ParentProductCategoryID])VALUES(12,'Boats',3)

INSERTINTO [TreeSource]([ProductCategoryID],[CatDescription],[ParentProductCategoryID])VALUES(13,'Automobiles',3)

INSERTINTO [TreeSource]([ProductCategoryID],[CatDescription],[ParentProductCategoryID])VALUES(14,'Jewelry',2)

INSERTINTO [TreeSource]([ProductCategoryID],[CatDescription],[ParentProductCategoryID])VALUES(15,'Keepsake',2)

INSERTINTO [TreeSource]([ProductCategoryID],[CatDescription],[ParentProductCategoryID])VALUES(16,'Specialty',2)

--step 0

CREATETABLE #Tree(

NodeintNOTNULLIDENTITY(100, 1),

ParentNodeint,

ProductCategoryIDintNOTNULL,

Depthtinyint,

Lineagevarchar(50))

--step 1

INSERTINTO #Tree(ProductCategoryID)SELECT ProductCategoryIDFROM TreeSourceORDERBY ParentProductCategoryID,CatDescription

Go

UPDATE TSET T.ParentNode=P.Node

FROM dbo.#Tree T

INNERJOIN TreeSource EON T.ProductCategoryID=E.ProductCategoryID

INNERJOIN TreeSource BON E.ParentProductCategoryID=B.ProductCategoryID

INNERJOIN dbo.#Tree PON B.ProductCategoryID=P.ProductCategoryID

GO

--step 3

UPDATE #TreeSET Lineage='.', Depth=0WHERE ParentNodeIsNull

--step 4

WHILEEXISTS(SELECT*FROM #TreeWHERE DepthIsNull)

UPDATE TSET T.depth= P.Depth+ 1,

T.Lineage= P.Lineage+Ltrim(Str(T.ParentNode,4,0))+'.'

FROM #TreeAS T

INNERJOIN #TreeAS PON(T.ParentNode=P.Node)

WHERE P.Depth>=0

AND P.LineageIsNotNull

AND T.DepthIsNull

--step 5 final

SELECTSpace(T.Depth*4)+ E.CatDescriptionASName

FROM TreeSource E

INNERJOIN #Tree TON E.ProductCategoryID=T.ProductCategoryID

ORDERBY T.Lineage+Ltrim(Str(T.Node,6,0))

--SELECT * FROM #Tree

DROPTable #Tree

--read more http://www.sqlteam.com/item.asp?ItemID=8866

Friday, March 9, 2012

Retrieving all Child and Grandchild and Great Grandchild etc Nodes

Given this table:
CREATE TABLE Nodes (
[NodeID] [int] IDENTITY (1, 1) NOT NULL ,
[NodeName] [varchar] (50) NOT NULL ,
[ParentNodeID] [int] NULL ,
[SequenceUnderParent] [int] NULL
)
I would like to have one SELECT statement, if possible, that returns [all of
the descendent nodes] of a given node -- i.e., all of the given node's child
nodes AND all of their child nodes {grand child nodes}, etc... down to 4
possible "generations".
NOTE: It will not be possible (per "business rules" and of course the table
structure, obviously) for any node to have more than one parent node.
If not in one SELECT statement, then how can I accomplish this?
Thanks!See another post few poasts before
Bill of material (SQL2000)
"Jordan S." <A@.B.COM> wrote in message
news:%23$fKXzkXGHA.4212@.TK2MSFTNGP02.phx.gbl...
> Given this table:
> CREATE TABLE Nodes (
> [NodeID] [int] IDENTITY (1, 1) NOT NULL ,
> [NodeName] [varchar] (50) NOT NULL ,
> [ParentNodeID] [int] NULL ,
> [SequenceUnderParent] [int] NULL
> )
> I would like to have one SELECT statement, if possible, that returns [all
> of the descendent nodes] of a given node -- i.e., all of the given node's
> child nodes AND all of their child nodes {grand child nodes}, etc... down
> to 4 possible "generations".
> NOTE: It will not be possible (per "business rules" and of course the
> table structure, obviously) for any node to have more than one parent
> node.
> If not in one SELECT statement, then how can I accomplish this?
> Thanks!
>|||There are many ways to represent a tree or hierarchy in SQL. This is
called an adjacency list model and it looks like this:
CREATE TABLE OrgChart
(emp CHAR(10) NOT NULL PRIMARY KEY,
boss CHAR(10) DEFAULT NULL REFERENCES OrgChart(emp),
salary DECIMAL(6,2) NOT NULL DEFAULT 100.00);
OrgChart
emp boss salary
===========================
'Albert' NULL 1000.00
'Bert' 'Albert' 900.00
'Chuck' 'Albert' 900.00
'Donna' 'Chuck' 800.00
'Eddie' 'Chuck' 700.00
'Fred' 'Chuck' 600.00
Another way of representing trees is to show them as nested sets.
Since SQL is a set oriented language, this is a better model than the
usual adjacency list approach you see in most text books. Let us define
a simple OrgChart table like this.
CREATE TABLE OrgChart
(emp CHAR(10) NOT NULL PRIMARY KEY,
lft INTEGER NOT NULL UNIQUE CHECK (lft > 0),
rgt INTEGER NOT NULL UNIQUE CHECK (rgt > 1),
CONSTRAINT order_okay CHECK (lft < rgt) );
OrgChart
emp lft rgt
======================
'Albert' 1 12
'Bert' 2 3
'Chuck' 4 11
'Donna' 5 6
'Eddie' 7 8
'Fred' 9 10
The organizational chart would look like this as a directed graph:
Albert (1, 12)
/ \
/ \
Bert (2, 3) Chuck (4, 11)
/ | \
/ | \
/ | \
/ | \
Donna (5, 6) Eddie (7, 8) Fred (9, 10)
The adjacency list table is denormalized in several ways. We are
modeling both the Personnel and the organizational chart in one table.
But for the sake of saving space, pretend that the names are job titles
and that we have another table which describes the Personnel that hold
those positions.
Another problem with the adjacency list model is that the boss and
employee columns are the same kind of thing (i.e. names of personnel),
and therefore should be shown in only one column in a normalized table.
To prove that this is not normalized, assume that "Chuck" changes his
name to "Charles"; you have to change his name in both columns and
several places. The defining characteristic of a normalized table is
that you have one fact, one place, one time.
The final problem is that the adjacency list model does not model
subordination. Authority flows downhill in a hierarchy, but If I fire
Chuck, I disconnect all of his subordinates from Albert. There are
situations (i.e. water pipes) where this is true, but that is not the
expected situation in this case.
To show a tree as nested sets, replace the nodes with ovals, and then
nest subordinate ovals inside each other. The root will be the largest
oval and will contain every other node. The leaf nodes will be the
innermost ovals with nothing else inside them and the nesting will show
the hierarchical relationship. The (lft, rgt) columns (I cannot use the
reserved words LEFT and RIGHT in SQL) are what show the nesting. This
is like XML, HTML or parentheses.
At this point, the boss column is both redundant and denormalized, so
it can be dropped. Also, note that the tree structure can be kept in
one table and all the information about a node can be put in a second
table and they can be joined on employee number for queries.
To convert the graph into a nested sets model think of a little worm
crawling along the tree. The worm starts at the top, the root, makes a
complete trip around the tree. When he comes to a node, he puts a
number in the cell on the side that he is visiting and increments his
counter. Each node will get two numbers, one of the right side and one
for the left. Computer Science majors will recognize this as a modified
preorder tree traversal algorithm. Finally, drop the unneeded
OrgChart.boss column which used to represent the edges of a graph.
This has some predictable results that we can use for building queries.
The root is always (left = 1, right = 2 * (SELECT COUNT(*) FROM
TreeTable)); leaf nodes always have (left + 1 = right); subtrees are
defined by the BETWEEN predicate; etc. Here are two common queries
which can be used to build others:
1. An employee and all their Supervisors, no matter how deep the tree.
SELECT O2.*
FROM OrgChart AS O1, OrgChart AS O2
WHERE O1.lft BETWEEN O2.lft AND O2.rgt
AND O1.emp = :myemployee;
2. The employee and all their subordinates. There is a nice symmetry
here.
SELECT O1.*
FROM OrgChart AS O1, OrgChart AS O2
WHERE O1.lft BETWEEN O2.lft AND O2.rgt
AND O2.emp = :myemployee;
3. Add a GROUP BY and aggregate functions to these basic queries and
you have hierarchical reports. For example, the total salaries which
each employee controls:
SELECT O2.emp, SUM(S1.salary)
FROM OrgChart AS O1, OrgChart AS O2,
Salaries AS S1
WHERE O1.lft BETWEEN O2.lft AND O2.rgt
AND O1.emp = S1.emp
GROUP BY O2.emp;
4. To find the level of each emp, so you can print the tree as an
indented listing. Technically, you should declare a cursor to go with
the ORDER BY clause.
SELECT COUNT(O2.emp) AS indentation, O1.emp
FROM OrgChart AS O1, OrgChart AS O2
WHERE O1.lft BETWEEN O2.lft AND O2.rgt
GROUP BY O1.lft, O1.emp
ORDER BY O1.lft;
5. The nested set model has an implied ordering of siblings which the
adjacency list model does not. To insert a new node, G1, under part G.
We can insert one node at a time like this:
BEGIN ATOMIC
DECLARE rightmost_spread INTEGER;
SET rightmost_spread
= (SELECT rgt
FROM Frammis
WHERE part = 'G');
UPDATE Frammis
SET lft = CASE WHEN lft > rightmost_spread
THEN lft + 2
ELSE lft END,
rgt = CASE WHEN rgt >= rightmost_spread
THEN rgt + 2
ELSE rgt END
WHERE rgt >= rightmost_spread;
INSERT INTO Frammis (part, lft, rgt)
VALUES ('G1', rightmost_spread, (rightmost_spread + 1));
COMMIT WORK;
END;
The idea is to spread the (lft, rgt) numbers after the youngest child
of the parent, G in this case, over by two to make room for the new
addition, G1. This procedure will add the new node to the rightmost
child position, which helps to preserve the idea of an age order among
the siblings.
6. To convert a nested sets model into an adjacency list model:
SELECT B.emp AS boss, E.emp
FROM OrgChart AS E
LEFT OUTER JOIN
OrgChart AS B
ON B.lft
= (SELECT MAX(lft)
FROM OrgChart AS S
WHERE E.lft > S.lft
AND E.lft < S.rgt);
7. To convert an adjacency list to a nested set model, use a push down
stack. Here is version with a stack in SQL/PSM.
-- Tree holds the adjacency model
CREATE TABLE Tree
(node CHAR(10) NOT NULL,
parent CHAR(10));
-- Stack starts empty, will holds the nested set model
CREATE TABLE Stack
(stack_top INTEGER NOT NULL,
node CHAR(10) NOT NULL,
lft INTEGER,
rgt INTEGER);
CREATE PROCEDURE TreeTraversal ()
LANGUAGE SQL
DETERMINISTIC
BEGIN ATOMIC
DECLARE counter INTEGER;
DECLARE max_counter INTEGER;
DECLARE current_top INTEGER;
SET counter = 2;
SET max_counter = 2 * (SELECT COUNT(*) FROM Tree);
SET current_top = 1;
--clear the stack
DELETE FROM Stack;
-- push the root
INSERT INTO Stack
SELECT 1, node, 1, max_counter
FROM Tree
WHERE parent IS NULL;
-- delete rows from tree as they are used
DELETE FROM Tree WHERE parent IS NULL;
WHILE counter <= max_counter- 1
DO IF EXISTS (SELECT *
FROM Stack AS S1, Tree AS T1
WHERE S1.node = T1.parent
AND S1.stack_top = current_top)
THEN BEGIN -- push when top has subordinates and set lft value
INSERT INTO Stack
SELECT (current_top + 1), MIN(T1.node), counter, NULL
FROM Stack AS S1, Tree AS T1
WHERE S1.node = T1.parent
AND S1.stack_top = current_top;
-- delete rows from tree as they are used
DELETE FROM Tree
WHERE node = (SELECT node
FROM Stack
WHERE stack_top = current_top + 1);
-- housekeeping of stack pointers and counter
SET counter = counter + 1;
SET current_top = current_top + 1;
END;
ELSE
BEGIN -- pop the stack and set rgt value
UPDATE Stack
SET rgt = counter,
stack_top = -stack_top -- pops the stack
WHERE stack_top = current_top;
SET counter = counter + 1;
SET current_top = current_top - 1;
END;
END IF;
END WHILE;
-- SELECT node, lft, rgt FROM Stack;
-- the top column is not needed in the final answer
-- move stack contents to new tree table
END;
I have a book on TREES & HIERARCHIES IN SQL which you can get at
Amazon.com right now.

Saturday, February 25, 2012

Retrieve Identity on insert: what if table has 2 identity columns

I have a table with 2 identity columns:
ID int identity(200100,1) not null,
OrderNo int Identity(550000,1) not null,
OrderName varchar(60) not null,
etc.
How do I get the values set by SQL server for ID and OrderNo when I insert
a new row in the table ?
Thanks in advance,Eve
If you are sitting on SQL Server 2000 then perform after inserting
SELECT SCOPE_IDENTITY()
Otherwise SELECT @.@.IDENTITY
"Eve" <Eve@.discussions.microsoft.com> wrote in message
news:F1824CDF-BC5D-4E89-98DA-6364A036B577@.microsoft.com...
> I have a table with 2 identity columns:
> ID int identity(200100,1) not null,
> OrderNo int Identity(550000,1) not null,
> OrderName varchar(60) not null,
> etc.
> How do I get the values set by SQL server for ID and OrderNo when I
insert
> a new row in the table ?
> Thanks in advance,
>|||It seems that there is a relationship between the two numbers.Seeing as you
can't have two identity columns. Why don't you use a formula for the ordern
o
Alter table <table> add OrderNo As ID + 300000.
"Eve" wrote:

> I have a table with 2 identity columns:
> ID int identity(200100,1) not null,
> OrderNo int Identity(550000,1) not null,
> OrderName varchar(60) not null,
> etc.
> How do I get the values set by SQL server for ID and OrderNo when I inser
t
> a new row in the table ?
> Thanks in advance,
>|||And on another note. I can't see why you need and ID since the OrderNo is
already unique...
Why is this ?
"Eve" wrote:

> I have a table with 2 identity columns:
> ID int identity(200100,1) not null,
> OrderNo int Identity(550000,1) not null,
> OrderName varchar(60) not null,
> etc.
> How do I get the values set by SQL server for ID and OrderNo when I inser
t
> a new row in the table ?
> Thanks in advance,
>|||I think you are mistaken. Only one IDENTITY column per table is permitted.
Please post the CREATE TABLE statement for your table so that we can
understand what you mean.
In SQL Server 2000 use SCOPE_IDENTITY() to retrieve the last inserted
IDENTITY value.
David Portas
SQL Server MVP
--

Retrieve good records from a bad record table

I have a situation where I need a table if bad items to match to. For
example, The main table may be as:

Table Main:
fd_Id INT IDENTITY (1, 1)
fd_Type VARCHAR(100)

Table Matcher:
fd_SubType VARCHAR(20)

Table Main might have a records like:
1 | "This is some full amount of text"
2 | "Here is half amount of text"
3 | "Some more with a catch word"

Table Matcher:
"full"
"catch"

I need to only get the records from the main table that do not have
anything in the match table. This should return only record 2.Verticon:: (miben@.miben.net) writes:
> I have a situation where I need a table if bad items to match to. For
> example, The main table may be as:
> Table Main:
> fd_Id INT IDENTITY (1, 1)
> fd_Type VARCHAR(100)
> Table Matcher:
> fd_SubType VARCHAR(20)
> Table Main might have a records like:
> 1 | "This is some full amount of text"
> 2 | "Here is half amount of text"
> 3 | "Some more with a catch word"
> Table Matcher:
> "full"
> "catch"
> I need to only get the records from the main table that do not have
> anything in the match table. This should return only record 2.

SELECT mn.fd_id, mn.fd_Type
FROM tablemain mn
WHERE NOT EXISTS (SELECT *
FROM tablematcher mt
WHERE md.fd_Type LIKE '%' + mt.fd_SubType + '%')

--
Erland Sommarskog, SQL Server MVP, esquel@.sommarskog.se

Books Online for SQL Server 2005 at
http://www.microsoft.com/technet/pr...oads/books.mspx
Books Online for SQL Server 2000 at
http://www.microsoft.com/sql/prodin...ions/books.mspx