Showing posts with label datatype. Show all posts
Showing posts with label datatype. Show all posts

Wednesday, March 28, 2012

Property Promotion with multi-level XML data type

How would you extract data from an XML datatype column when it has multiple levels? I've done this with single levels using CROSS APPLY and the nodes method, but can't seem to grab data from the intermediate levels.

Example:

<Level1>

<Level2>xyz</Level2>

<Level2>xyz</Level2>

<Level3>abc</Level3>

<Level3>abc</Level3>

<Level3>abc</Level3>

<Level2>xyz</Level2>

<Level2>xyz</Level2>

</Level1>

For the root level, I use the xml.value() function, and for the details I use the cross apply xml.nodes() function typically, but if I use the xpath in the xml.nodes, I have to use the path to the lowest level (level3) to grab those values, but can't seem to grab the changing values at the intermediate levels (level2).

Would this involve multiple cross-apply instances?

I don't understand your example, why are those Level3 elements indented further to the right than the Level2 elements? They are both children of the root element Level1.

And it is not obvious what you want to extract.

|||

Sorry if this wasn't clear. The XML is supposed to represent a multiple-level heirarchy and the indentation indicates a parent-child relationship.

So level 1 can be Order, for example. At this level there can be several elements that define the Order (ID, Cust #, etc). Level 2 would be Order Type, like Internal, External, Global, Domestic (each order always has these 4 types associated with it). Level 3 would be details relevant to that order detail item, like part #, quantity, etc. (each Order has 4 Order Types, of which have multiple line-items within each order type).

So I need to return a table of data based on this single order. The results returned would have these fields:

Order ID (repeated for every order detail)

Cust # (repeated for every order detail)

OrderType (repeated for every order type/order detail)

Part # (unique per order detail/type)

Qty (unique per order detail/type)

Analogous to joining three relational tables (Order details -> Order Type -> Order) and getting the combined results of all three.

In SQL xquery, I use the .value function to get the Order ID and Cust# because they are at the root level of the XML field. I use the CROSS APPLY .nodes method to get to the lowest level of detail (Part# and Qty) and this produces the correct data. But for the intermediate level (Order Type) I can't seem to get to it.

If it still isn't clear, I'll send some actual XML.

Thanks

Kory

|||

Consider posting the XML and the query you have, then we can work from there to improve it.

|||

A coworker of mine helped me to figure this out:

I was doing this:

Before

With Namespaces(....)
select
t.EventDateTime
,t.OrderId

,ref.value('(//gns:OrderType/text())[1]','varchar(max)') OrderType
,ref.value('(ns:Product/text())[1]','varchar(max)') Product
,ref.value('(ns:Qty/text())[1]','varchar(max)') Qty
FROM
Orders t
CROSS APPLY
xmlfld.nodes ('//ns:OrderDetailItem') AS R(ref)

And we changed it to this:

After

With Namespaces(....)
select
t.EventDateTime
,t.OrderId

,ref.value('(http://gns:OrderType/text())[1]','varchar(max)') OrderType

,ref.value('(//gns:OrderType/text())[1]','varchar(max)') OrderType
,ref.value('(ns:Product/text())[1]','varchar(max)') Product
,ref.value('(ns:Qty/text())[1]','varchar(max)') Qty
FROM
Orders t
CROSS APPLY
xmlfld.nodes ('//ns:OrderDetailItem') AS R(ref)

So the only change was to the xpath from //gnsSurpriserderType to http://gnsSurpriserderType

I really don't understand why this worked, but the first way just promoted the first occurance of the value, but the second method promoted the value when it changed.

-Kory

Monday, March 26, 2012

Properly copying data of datatype Image

I have a column called "Image" in a table that stores all the user information. Image holds the data for the user's badge photo. I'm currently working on a project to move some of the data from the users table to more relevant tables. With the SQL script I wrote to copy the data into the new tables the image data appears to not have been transferred correctly. I had tried storing the image data into a variable of type varbinary(8000) before inserting it back in. Is there a certain datatype that must be used to store the data when reading from a column of data type "image" and then inserting it into another column of data type "image" without getting truncation or corruption of the data?

Can you please try the following?

HOWTO: Read and Write BLOBs Using GetChunk and AppendChunk
http://support.microsoft.com/default.aspx?scid=kb;en-us;194975
HOWTO: Access and Modify SQL Server BLOB Data by Using the ADO Stream Object
http://support.microsoft.com/default.aspx?scid=kb;EN-US;q258038
How To Read and Write BLOB Data by Using ADO.NET with Visual Basic .NET
http://support.microsoft.com/kb/308042/EN-US

Monday, March 12, 2012

Programming Field Lengths

Is it possible to tell sql server to cast to a datatype and set the
field length to a variable.

e.g. :-

declare @.flen int
set @.flen = 10

select (cast somefield as char(@.flen) newfield)
into newtable
from sometable

I have also tried :-
select (cast somefield as char(max(len(somefield))) newfield)
into newtable
from sometable

When I try the above examples I get error in @.flen; error in max
respectivly.

TIA

Simon<bozzzza@.lycos.co.uk> wrote in message
news:1119438419.547258.218740@.z14g2000cwz.googlegr oups.com...
> Is it possible to tell sql server to cast to a datatype and set the
> field length to a variable.
> e.g. :-
> declare @.flen int
> set @.flen = 10
> select (cast somefield as char(@.flen) newfield)
> into newtable
> from sometable
> I have also tried :-
> select (cast somefield as char(max(len(somefield))) newfield)
> into newtable
> from sometable
> When I try the above examples I get error in @.flen; error in max
> respectivly.
> TIA
> Simon

I don't believe there's any easy way to do this, but in most cases, it's
probably not necessary - instead of declaring char(10), why not just declare
varchar(1000), or whatever value is suitable for you? If you can explain why
you need to do this, someone may have a better solution. Depending on what
you need to achieve, you might be able to use dynamic SQL, but that has a
number of issues:

http://www.sommarskog.se/dynamic_sql.html

Simon|||(bozzzza@.lycos.co.uk) writes:
> Is it possible to tell sql server to cast to a datatype and set the
> field length to a variable.
> e.g. :-
> declare @.flen int
> set @.flen = 10
> select (cast somefield as char(@.flen) newfield)
> into newtable
> from sometable
> I have also tried :-
> select (cast somefield as char(max(len(somefield))) newfield)
> into newtable
> from sometable
> When I try the above examples I get error in @.flen; error in max
> respectivly.

No, you would have to use dynamic SQL for that. Seems easier to use
varchar.

What do you want to achieve, really?

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

Books Online for SQL Server SP3 at
http://www.microsoft.com/sql/techin.../2000/books.asp|||
Erland Sommarskog wrote:
> (bozzzza@.lycos.co.uk) writes:
> > Is it possible to tell sql server to cast to a datatype and set the
> > field length to a variable.
> > e.g. :-
> > declare @.flen int
> > set @.flen = 10
> > select (cast somefield as char(@.flen) newfield)
> > into newtable
> > from sometable
> > I have also tried :-
> > select (cast somefield as char(max(len(somefield))) newfield)
> > into newtable
> > from sometable
> > When I try the above examples I get error in @.flen; error in max
> > respectivly.
> No, you would have to use dynamic SQL for that. Seems easier to use
> varchar.
> What do you want to achieve, really?

Yhe problem is we have had some data supplied and the all the fields
lengths are set to 255 (nvarchar), even though this is not good pratice
we could live with it until someone else wanted a fixed length export
of the data.

So my idea was to work out the length of the fields and insert them as
the maximum width into the new table. Then the fixed length file would
look a lot better and cleaner.

Thanks for the reply, I will look into Dynamic SQL.|||(bozzzza@.lycos.co.uk) writes:
> Yhe problem is we have had some data supplied and the all the fields
> lengths are set to 255 (nvarchar), even though this is not good pratice
> we could live with it until someone else wanted a fixed length export
> of the data.
> So my idea was to work out the length of the fields and insert them as
> the maximum width into the new table. Then the fixed length file would
> look a lot better and cleaner.

Maybe. But what if the max lengths you find do agree with the actual
business rules? Next time you get a refresh, you could get an error
because of truncation.

So I would suggest that either you find out the actual max lengths, or
you leave the table the way it is.

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

Books Online for SQL Server SP3 at
http://www.microsoft.com/sql/techin.../2000/books.asp|||You have asked the same question in
microsoft.public.sqlserver.programming. Please don't post the same
question independently to diffferent groups. It's inconsiderate to
others who may waste time responding on something that has already been
answered elsewhere.

In your other thread you indicated that your intention is to
standardize the column sizes for reporting purposes. All the reporting
tools I know of allow you to specify a field width shorter than the
actual column width so I'm not sure why you would want to do this in
SQL. Keep it in the presentation tier is my suggestion.

--
David Portas
SQL Server MVP
--|||
David Portas wrote:
> You have asked the same question in
> microsoft.public.sqlserver.programming. Please don't post the same
> question independently to diffferent groups. It's inconsiderate to
> others who may waste time responding on something that has already been
> answered elsewhere.

Sorry.

> In your other thread you indicated that your intention is to
> standardize the column sizes for reporting purposes. All the reporting
> tools I know of allow you to specify a field width shorter than the
> actual column width so I'm not sure why you would want to do this in
> SQL. Keep it in the presentation tier is my suggestion.

Actually I needed to create a fix length text file of the data, so a
pascal programmer could import it into a DOS application, and the
programmer wasn't happy that the fields were coming out at 255 each.

After reading Erland's post, I gave the programmer the export in Comma
delimited format instead, so a refresh of the data won't effect the
export.

But thanks to all the posts I now know dynamic sql exists (I thought
exec was just for stored procedures) and it has opened up a whole new
world for me.|||Yes it is possible!

Do it this way!

eg :-

declare @.flen int
set @.flen = 10

exec('select cast(somefield as char(' + @.flen + ')) as newfield into
newtable
from oldtable')

Regards
Debian

*** Sent via Developersdex http://www.developersdex.com ***|||> I now know dynamic sql exists (I thought
> exec was just for stored procedures) and it has opened up a whole new
> world for me.

Make sure you understand the implications. Dynamic SQL should usually
be a last resort in production code. See:
http://www.sommarskog.se/dynamic_sql.html

--
David Portas
SQL Server MVP
--