Showing posts with label containing. Show all posts
Showing posts with label containing. Show all posts

Monday, March 12, 2012

nested FOR XML queries / with namespaces

I want to assign the result of a FOR XML query containing nested queries to an xml variable. The problem is, the namespace declarations propagate down to every nested element generated in the query.

DECLARE @.x xml
BEGIN
WITH XMLNAMESPACES('one' AS ns1, 'two' AS ns2)
SELECT @.x = (
SELECT -1 "@.id",
'invalid' "@.status",
(SELECT 'false' "@.flag",
'etc' "@.comment"
FOR XML PATH ('ns2:inner'), TYPE)
FOR XML PATH('ns1:0uter'), TYPE);
SELECT @.x
END;

This is the XML that is generated:

<ns1:0uter xmlns:ns2="two" xmlns:ns1="one" id="-1" status="invalid">
<ns2:inner xmlns:ns2="two" xmlns:ns1="one" flag="false" comment="etc" />
</ns1:0uter>

Is there an alternate way to declare a namespace in a nested query (in this case, move the namespace declaration for 'two AS ns2' out of the outer query into the nested select)? If not, then are there alternative ways to remove this extraneous stuff? This is a simple example, but real-world instances involving several levels of nesting these declarations are too much.

I have the same question. I simply need to add

xmlns="urn:xxxx.yyyyy.zzzzz"

in the header of the XML only.

I review the MDSN details: http://msdn2.microsoft.com/en-us/library/ms177400.aspx but don't see how to accomplish this simple thing.

I can't even fake it out:

SELECT

'en-US' AS "MessageLanguage",

'2007-05-08T18:13:51.0Z' AS "IssueDate",

'urn:xxxx.yyyyy.zzzzz' AS "@.xmlns",

The select returns error:

'xmlns' is invalid in XML tag name in FOR XML PATH, or when WITH XMLNAMESPACES is used with FOR XML.

|||

I have the same problem with this query:

Code Snippet

declare @.category_name as varchar(512);
set @.category_name = 'Bolt';

with xmlnamespaces ('http://services.ihs.com/schemas/structured_content' as sc)

select id as [@.sc:id], 'ADD' as [@.sc:action], cat_id as [@.sc:categoryId],

(select attribute_id as [@.sc:attributeId], value as [data()]

from Item_Detail (nolock)

where item_id = Item.id

for xml path('sc:VALUE'), type)

from Item (nolock)

where cat_id = (select id from Category (nolock) where name = @.category_name)

for xml path('sc:ITEM'), root('sc:ITEMS')
;

Each of the 22 million nested sc:VALUE result elements unnecessarily rebind the namespace prefix:

Code Snippet

<sc:ITEMS xmlns:sc="http://services.ihs.com/schemas/structured_content">

<sc:ITEM sc:id="ABE9639D-3C7B-4E66-BF32-00001A294577" sc:action="ADD" sc:categoryId="68541B13-9C60-4D90-B694-68C28F346832">

<sc:VALUE xmlns:sc="http://services.ihs.com/schemas/structured_content" sc:attributeId="E9BD274C-34C2-44A1-8F54-6E5218C71A9A">STEEL ALLOY</sc:VALUE>

...

nested FOR XML queries / with namespaces

I want to assign the result of a FOR XML query containing nested queries to an xml variable. The problem is, the namespace declarations propagate down to every nested element generated in the query.

DECLARE @.x xml
BEGIN
WITH XMLNAMESPACES('one' AS ns1, 'two' AS ns2)
SELECT @.x = (
SELECT -1 "@.id",
'invalid' "@.status",
(SELECT 'false' "@.flag",
'etc' "@.comment"
FOR XML PATH ('ns2:inner'), TYPE)
FOR XML PATH('ns1:0uter'), TYPE);
SELECT @.x
END;

This is the XML that is generated:

<ns1:0uter xmlns:ns2="two" xmlns:ns1="one" id="-1" status="invalid">
<ns2:inner xmlns:ns2="two" xmlns:ns1="one" flag="false" comment="etc" />
</ns1:0uter>

Is there an alternate way to declare a namespace in a nested query (in this case, move the namespace declaration for 'two AS ns2' out of the outer query into the nested select)? If not, then are there alternative ways to remove this extraneous stuff? This is a simple example, but real-world instances involving several levels of nesting these declarations are too much.

I have the same question. I simply need to add

xmlns="urn:xxxx.yyyyy.zzzzz"

in the header of the XML only.

I review the MDSN details: http://msdn2.microsoft.com/en-us/library/ms177400.aspx but don't see how to accomplish this simple thing.

I can't even fake it out:

SELECT

'en-US' AS "MessageLanguage",

'2007-05-08T18:13:51.0Z' AS "IssueDate",

'urn:xxxx.yyyyy.zzzzz' AS "@.xmlns",

The select returns error:

'xmlns' is invalid in XML tag name in FOR XML PATH, or when WITH XMLNAMESPACES is used with FOR XML.

|||

I have the same problem with this query:

Code Snippet

declare @.category_name as varchar(512);
set @.category_name = 'Bolt';

with xmlnamespaces ('http://services.ihs.com/schemas/structured_content' as sc)

select id as [@.sc:id], 'ADD' as [@.sc:action], cat_id as [@.sc:categoryId],

(select attribute_id as [@.sc:attributeId], value as [data()]

from Item_Detail (nolock)

where item_id = Item.id

for xml path('sc:VALUE'), type)

from Item (nolock)

where cat_id = (select id from Category (nolock) where name = @.category_name)

for xml path('sc:ITEM'), root('sc:ITEMS')
;

Each of the 22 million nested sc:VALUE result elements unnecessarily rebind the namespace prefix:

Code Snippet

<sc:ITEMS xmlns:sc="http://services.ihs.com/schemas/structured_content">

<sc:ITEM sc:id="ABE9639D-3C7B-4E66-BF32-00001A294577" sc:action="ADD" sc:categoryId="68541B13-9C60-4D90-B694-68C28F346832">

<sc:VALUE xmlns:sc="http://services.ihs.com/schemas/structured_content" sc:attributeId="E9BD274C-34C2-44A1-8F54-6E5218C71A9A">STEEL ALLOY</sc:VALUE>

...

nested FOR XML queries / with namespaces

I want to assign the result of a FOR XML query containing nested queries to an xml variable. The problem is, the namespace declarations propagate down to every nested element generated in the query.

DECLARE @.x xml
BEGIN
WITH XMLNAMESPACES('one' AS ns1, 'two' AS ns2)
SELECT @.x = (
SELECT -1 "@.id",
'invalid' "@.status",
(SELECT 'false' "@.flag",
'etc' "@.comment"
FOR XML PATH ('ns2:inner'), TYPE)
FOR XML PATH('ns1:0uter'), TYPE);
SELECT @.x
END;

This is the XML that is generated:

<ns1:0uter xmlns:ns2="two" xmlns:ns1="one" id="-1" status="invalid">
<ns2:inner xmlns:ns2="two" xmlns:ns1="one" flag="false" comment="etc" />
</ns1:0uter>

Is there an alternate way to declare a namespace in a nested query (in this case, move the namespace declaration for 'two AS ns2' out of the outer query into the nested select)? If not, then are there alternative ways to remove this extraneous stuff? This is a simple example, but real-world instances involving several levels of nesting these declarations are too much.

I have the same question. I simply need to add

xmlns="urn:xxxx.yyyyy.zzzzz"

in the header of the XML only.

I review the MDSN details: http://msdn2.microsoft.com/en-us/library/ms177400.aspx but don't see how to accomplish this simple thing.

I can't even fake it out:

SELECT

'en-US' AS "MessageLanguage",

'2007-05-08T18:13:51.0Z' AS "IssueDate",

'urn:xxxx.yyyyy.zzzzz' AS "@.xmlns",

The select returns error:

'xmlns' is invalid in XML tag name in FOR XML PATH, or when WITH XMLNAMESPACES is used with FOR XML.

|||

I have the same problem with this query:

Code Snippet

declare @.category_name as varchar(512);
set @.category_name = 'Bolt';

with xmlnamespaces ('http://services.ihs.com/schemas/structured_content' as sc)

select id as [@.sc:id], 'ADD' as [@.sc:action], cat_id as [@.sc:categoryId],

(select attribute_id as [@.sc:attributeId], value as [data()]

from Item_Detail (nolock)

where item_id = Item.id

for xml path('sc:VALUE'), type)

from Item (nolock)

where cat_id = (select id from Category (nolock) where name = @.category_name)

for xml path('sc:ITEM'), root('sc:ITEMS')
;

Each of the 22 million nested sc:VALUE result elements unnecessarily rebind the namespace prefix:

Code Snippet

<sc:ITEMS xmlns:sc="http://services.ihs.com/schemas/structured_content">

<sc:ITEM sc:id="ABE9639D-3C7B-4E66-BF32-00001A294577" sc:action="ADD" sc:categoryId="68541B13-9C60-4D90-B694-68C28F346832">

<sc:VALUE xmlns:sc="http://services.ihs.com/schemas/structured_content" sc:attributeId="E9BD274C-34C2-44A1-8F54-6E5218C71A9A">STEEL ALLOY</sc:VALUE>

...

Friday, March 9, 2012

negative values when calculating percentages

I get negative values for percentage calculation in a MDX query. The MDX query has a crossjoin between two sets containing calculated members from the same dimension, one of the calculated members being a percentage value. I'm not sure why some of the percentage values are negative.

Another problem I'm facing is that the percentage value is not being displayed as per the FORMAT_STRING property, in my Reports in Reporting Services 2005 that use the data generated by the MDX query.

Any help or suggestion is appreciated.

Hi. Can we see the MDX query you're using and a small data sample which provides the negative percentage?

PGoldy

|||

Hope this will give you an idea:

WITH
MEMBER [ITEMA].[ITEMA].itemmember
as

' (ITEMA.ITEMA.&[itemmember], [Measures].[NUMBER]) '

MEMBER [ITEMA].[ITEMA].TOTAL
as

' SUM(ITEMA.ITEMA.Members, [Measures].[NUMBERS]) '

MEMBER [ITEMA].[ITEMA].ITEMPERC
as

' Iif(IsEmpty([ITEMA].[ITEMA].TOTAL),0,([ITEMA].[ITEMA].itemmember / [ITEMA].[ITEMA].TOTAL)) ', FORMAT_STRING = '#.#%'

select [Measures].[NUMBER] on columns,

non empty crossjoin({[ITEMA].[ITEMA].MEMBERS,[ITEMA].[ITEMA].OTHERS,[ITEMA].[ITEMA].itemmember,[ITEMA].[ITEMA].TOTAL,[ITEMA].[ITEMA].ITEMPERC},
crossjoin({ITEMB.ITEMB.children},{ITEMC.ITEMC.children,[ITEMC].[ITEMC].[others]})) on rows
FROM [MyCube]

Data Snapshot:

ITEMA_1 ITEMA_2 ........ ITEMA_itemmember ITEMA_TOTAL ITEMA_ITEMPERC

- ITEMB_1
ITEMC_1 10 20 10 100 -0.1
ITEMC_2 5 6 0 150 0.0
ITEMC_3 0 1 2 4 0.5

- ITEMB_2
ITEMC_1 ...................................................................
ITEMC_2 ...................................................................
ITEMC_3 ...................................................................
+ ITEMB_3
+ ITEMB_4
.
.
.

|||

Hi. Thanks for the detailed query and example.

I don't see why you get a negative percentage, but I see you're using the calculated members to get values which are normally available in the cube without the use of a calculated member when you construct the right query. I think you should reconstruct your query to use the WHERE clause and re-define, and eliminate, some calculated members to get the correct results Here are my recommendations:

(1) Use the WHERE cluase to slice your qeury by the desired measure: WHERE (Measures.Number)

(2) Reference ITEMA dimension on the columns.

(3) Eliminate the following calculated members because they are not needed and we can derive the dsired values from normal intersections in the cube: (a) MEMBER [ITEMA].[ITEMA].itemmember, (b) MEMBER [ITEMA].[ITEMA].TOTAL

(4) Change the definition of MEMBER [ITEMA].[ITEMA].ITEMPERC to reference the correct cube intersections.

Assumption: ITEMA hierarchy has an "all" member, aggregation type for Measures.Number is SUM.

Here's the new query with the recommended changes:

WITH
MEMBER [ITEMA].[ITEMA].ITEMPERC AS
' Iif(IsEmpty([ITEMA].[ITEMA].[All ITEMA]),0,([ITEMA].[ITEMA].CurrentMember / [ITEMA].[ITEMA].[All ITEMA])) ', FORMAT_STRING = '0.0%'

NON EMPTY {[ITEMA].[ITEMA].MEMBERS, [ITEMA].[ITEMA].[All ITEMA], [ITEMA].[ITEMA].ITEMPERC} ON COLUMNS,
crossjoin({ITEMB.ITEMB.children},{ITEMC.ITEMC.children,[ITEMC].[ITEMC].[others]}) on rows
FROM [MyCube]
WHERE ([Measures].[NUMBER])

Hoe this helps.

PGoldy

Wednesday, March 7, 2012

needed: 1 + null = 1

Hi,

I need this behaviour: 1 + null = 1
I have a (dynamic) set of many columns containing decimals that I want
to add as follows:
if all columns are null the result should be null
if not all columns are null, the null columns may be regarded as 0.

E.g.
null + null + 1 = 1
null + null + null = null

The problem is that the first expression yields null.

Up till now I generated an update statement with isnull(<column>,0),
however, then the second expression yields 0.
I can add another update statment setting the result to null if all
columns are null, but this is very slow, and not very intuitive
either.
How nice it would be if there were a setting like 'concat null yields
null' for arithmetic operators.

Anyone any idea how to fix this?

Thanks.
Paulinfo@.vanoordt.nl wrote in news:1180430739.196981.227870
@.q69g2000hsb.googlegroups.com:

Quote:

Originally Posted by

Hi,
>
I need this behaviour: 1 + null = 1
I have a (dynamic) set of many columns containing decimals that I want
to add as follows:
if all columns are null the result should be null
if not all columns are null, the null columns may be regarded as 0.
>
E.g.
null + null + 1 = 1
null + null + null = null
>
The problem is that the first expression yields null.
>
Up till now I generated an update statement with isnull(<column>,0),
however, then the second expression yields 0.
I can add another update statment setting the result to null if all
columns are null, but this is very slow, and not very intuitive
either.
How nice it would be if there were a setting like 'concat null yields
null' for arithmetic operators.
>
Anyone any idea how to fix this?
>
Thanks.
Paul
>
>


COALESCE(Col1, 0) + COALESCE(Col2, 0) + COALESCE(Col3, 0) + COALESCE(Col1,
Col2, Col3)|||Using coalesce is the same sort of solution as using isnull. It
doesn't behave as my requirements state. In particular, the result
will be 0 if all inputs are null. It is required that the result be
null.
Thanks anyway.|||On May 29, 4:37 pm, i...@.vanoordt.nl wrote:

Quote:

Originally Posted by

Using coalesce is the same sort of solution as using isnull. It
doesn't behave as my requirements state. In particular, the result
will be 0 if all inputs are null. It is required that the result be
null.
Thanks anyway.


No. Did you test

Result will be null if all are null .
since
COALESCE(Col1, Col2, Col3) returns null and
0 + 0 + 0 + null is null
COALESCE takes more arguments and ISNULL only two

declare @.a table (col1 int,col2 int,col3 int)

insert into @.a values (1,null,null)
insert into @.a values (null,2,null)
insert into @.a values (null,null,3)
insert into @.a values (1,2,null)
insert into @.a values (null,2,3)
insert into @.a values (1,null,3)
insert into @.a values (null,null,null)

select COALESCE(Col1, 0) + COALESCE(Col2, 0) + COALESCE(Col3, 0) +
COALESCE(Col1,
Col2, Col3) from @.a

2
4
6
4
7
5
NULL|||On 29.05.2007 14:06, M A Srinivas wrote:

Quote:

Originally Posted by

On May 29, 4:37 pm, i...@.vanoordt.nl wrote:

Quote:

Originally Posted by

>Using coalesce is the same sort of solution as using isnull. It
>doesn't behave as my requirements state. In particular, the result
>will be 0 if all inputs are null. It is required that the result be
>null.
>Thanks anyway.


>
No. Did you test
>
Result will be null if all are null .
since
COALESCE(Col1, Col2, Col3) returns null and
0 + 0 + 0 + null is null
COALESCE takes more arguments and ISNULL only two
>
declare @.a table (col1 int,col2 int,col3 int)
>
insert into @.a values (1,null,null)
insert into @.a values (null,2,null)
insert into @.a values (null,null,3)
insert into @.a values (1,2,null)
insert into @.a values (null,2,3)
insert into @.a values (1,null,3)
insert into @.a values (null,null,null)
>
select COALESCE(Col1, 0) + COALESCE(Col2, 0) + COALESCE(Col3, 0) +
COALESCE(Col1,
Col2, Col3) from @.a
>
>
2
4
6
4
7
5
NULL


Now there is only the small issue that one of the column values is added
twice - and you do not know which one. Something like this is probably
better:

-- untested
SELECT CASE
WHEN COALESCE(col1, col2, col2) IS NULL
THEN NULL
ELSE
COALESCE(col1, 0) +
COALESCE(col2, 0) +
COALESCE(col3, 0)
END
...

Kind regards

robert|||Thanks for your reactions,
There is this problem with Srinivas' solution and the solution Robert
supplies is actually what I already proposed myself. Namely separating
the case where all columns are null from those cases where some ar not
null, and this is very slow. (I'm talking about hundreds of columns
and millions of rows.)
I was actually thinking more of a solution to ignore the nulls, rather
than on the fly setting them to 0.
More suggestions are appreciated.
Regards,
Paul|||Robert Klemme <shortcutter@.googlemail.comwrote in news:5c2k0eF2tfjc8U2
@.mid.individual.net:

Quote:

Originally Posted by

On 29.05.2007 14:06, M A Srinivas wrote:

Quote:

Originally Posted by

>On May 29, 4:37 pm, i...@.vanoordt.nl wrote:

Quote:

Originally Posted by

>>Using coalesce is the same sort of solution as using isnull. It
>>doesn't behave as my requirements state. In particular, the result
>>will be 0 if all inputs are null. It is required that the result be
>>null.
>>Thanks anyway.


>>
>No. Did you test
>>
>Result will be null if all are null .
>since
> COALESCE(Col1, Col2, Col3) returns null and
>0 + 0 + 0 + null is null
>COALESCE takes more arguments and ISNULL only two
>>
>declare @.a table (col1 int,col2 int,col3 int)
>>
>insert into @.a values (1,null,null)
>insert into @.a values (null,2,null)
>insert into @.a values (null,null,3)
>insert into @.a values (1,2,null)
>insert into @.a values (null,2,3)
>insert into @.a values (1,null,3)
>insert into @.a values (null,null,null)
>>
>select COALESCE(Col1, 0) + COALESCE(Col2, 0) + COALESCE(Col3, 0) +
>COALESCE(Col1,
>Col2, Col3) from @.a
>>
>>
>2
>4
>6
>4
>7
>5
>NULL


>
Now there is only the small issue that one of the column values is


added

Quote:

Originally Posted by

twice - and you do not know which one.


Oops yes! Sorry. Must put brain in gear before letting fingers loose on
keyboard. Thanks for picking this up.

Quote:

Originally Posted by

Something like this is probably
better:
>
-- untested
SELECT CASE
WHEN COALESCE(col1, col2, col2) IS NULL
THEN NULL
ELSE
COALESCE(col1, 0) +
COALESCE(col2, 0) +
COALESCE(col3, 0)
END
...
>
Kind regards
>
robert
>

|||>I was actually thinking more of a solution to ignore the nulls, rather than on the fly setting them to 0. <<

Update your entire database once. Add a non-null constraint to the
columns. This is a "mop the floor, and fix the leak" philosophy.

Kill the moron who screwed up the schema, so he cannot do this
again. This is preventative maintenance :)|||Paul, try this:

UPDATE ..
SET MyCol = (
SELECT SUM(Columns_which_might_contain_null)
FROM (
SELECT CAST(DynamicCol1 AS int) AS
Columns_which_might_contain_null
UNION ALL SELECT DynamicCol2
UNION ALL SELECT DynamicCol3
) T
)

Because

SELECT SUM(Columns_which_might_contain_null)
FROM (
SELECT CAST(NULL AS int) AS
Columns_which_might_contain_null
UNION ALL SELECT NULL
UNION ALL SELECT 1
) T

SELECT SUM(Columns_which_might_contain_null)
FROM (
SELECT CAST(NULL AS int) AS
Columns_which_might_contain_null
UNION ALL SELECT NULL
UNION ALL SELECT NULL
) T

----
1

(1 row(s) affected)

Warning: Null value is eliminated by an aggregate or other SET
operation.

----
NULL

(1 row(s) affected)

Warning: Null value is eliminated by an aggregate or other SET
operation.

Gert-Jan

info@.vanoordt.nl wrote:

Quote:

Originally Posted by

>
Hi,
>
I need this behaviour: 1 + null = 1
I have a (dynamic) set of many columns containing decimals that I want
to add as follows:
if all columns are null the result should be null
if not all columns are null, the null columns may be regarded as 0.
>
E.g.
null + null + 1 = 1
null + null + null = null
>
The problem is that the first expression yields null.
>
Up till now I generated an update statement with isnull(<column>,0),
however, then the second expression yields 0.
I can add another update statment setting the result to null if all
columns are null, but this is very slow, and not very intuitive
either.
How nice it would be if there were a setting like 'concat null yields
null' for arithmetic operators.
>
Anyone any idea how to fix this?
>
Thanks.
Paul

|||I should have written

COALESCE(Col1, 0) + COALESCE(Col2, 0) + COALESCE(Col3, 0) + 0*COALESCE
(Col1, Col2, Col3)|||On 29.05.2007 14:46, info@.vanoordt.nl wrote:

Quote:

Originally Posted by

There is this problem with Srinivas' solution and the solution Robert
supplies is actually what I already proposed myself. Namely separating
the case where all columns are null from those cases where some ar not
null, and this is very slow. (I'm talking about hundreds of columns
and millions of rows.)


That sounds scary. Who in heck invents a schema with /hundreds/ of
numeric columns? Does this make sense at all?

robert|||Try This

select ISNULL(null,0) + 1|||I like Chris' last idea:
COALESCE(Col1, 0) + COALESCE(Col2, 0) + COALESCE(Col3, 0) +
0*COALESCE(Col1, Col2, Col3)

This calculates the value in one expression. I expect it to perform
well, at least not much worse than without the last term.

Gert-Jan, I need some time to find out what your code does. With all
respect, it lacks the simplicity of the above solution.

Robert, it does make sense and the schema is build dynamically.

Thanks for your responses.|||On 31.05.2007 10:21, info@.vanoordt.nl wrote:

Quote:

Originally Posted by

Robert, it does make sense and the schema is build dynamically.


If you say so... To me this rather sounds like a case for

CREATE TABLE PARAMETERS (
item INT NOT NULL,
parameter_name VARCHAR(20) NOT NULL,
parameter_value INT NOT NULL,
PRIMARY KEY (
item,
parameter_name
)
)

Of course I don't know all the details...

Kind regards

robert|||info@.vanoordt.nl wrote:

Quote:

Originally Posted by

>
I like Chris' last idea:
COALESCE(Col1, 0) + COALESCE(Col2, 0) + COALESCE(Col3, 0) +
0*COALESCE(Col1, Col2, Col3)
>
This calculates the value in one expression. I expect it to perform
well, at least not much worse than without the last term.
>
Gert-Jan, I need some time to find out what your code does. With all
respect, it lacks the simplicity of the above solution.


The code assumes that you did not properly normalize your table. It
assumes that Col1, Col2 and Col3 basically have the same meaning, and
should have been modelled as three rows. So the query is transposes the
three columns to three rows. Then the standard behavior of the SUM
aggregate is used, in which means NULLs are skipped. The result will
always be a scalar, and the SUM of an empty set is NULL.

Gert-Jan|||Gert Jan, you have a point; sum() exactly does what is required.
Actually this is what I am investigating also, but it is a decision
with more implications.
Regards, Paul