Showing posts with label head. Show all posts
Showing posts with label head. Show all posts

Monday, March 26, 2012

Noob: Why does this Query work?

I'm wondering how/why this query works. Trying to get my head wrapped
around SQL. Basically the Query deletes from the Import table all
records that are already in FooStrings so that when I do an insert from
the FooStringsImport table into the FooStrings table, then I won't get
primary key violations.

DELETE FROM FooStringsImport
WHERE EXISTS
(SELECT * FROM FooStrings
WHERE FooStringsImport.FooKey = FooStrings.FooKey)

It seems to work fine, but I'm wondering about how the EXISTS keyword
works.

(SELECT * FROM FooStrings
WHERE FooStringsImport.FooKey = FooStrings.FooKey)
This part is going to return only records from FooStrings correct? Or
does it do a cartesian product since I've specified more than one table
in the WHERE statement?

I wonder if it only returns records in FooStrings, then I don't see how
a record from FooStringsImport would "EXISTS" in the records returned
from FooStrings.

The reason I wondered about the cartesian product is because, if only
FooStrings is specified in the FROM part of the SELECT statement, then
I was thinking it is only going to return FooString records. These
records would then be returned by the select statement to the WHERE
EXISTS, which would look for FooStringImport records, but would find
none because the select statement only returned FooString records.

I'm guessing maybe because it has to do a cartesian product to evaluate
the WHERE Pkey's equal, then the "SELECT *" just goes ahead and gets
ALL the fields, and not just those in FooStrings.

FooStrings and FooStringsImport are identically structured tables,
where the FooKey is set as the primary key in each table:

CREATE TABLE [dbo].[FooStrings] (
[FooKey] [bigint] NOT NULL ,
[Name] [char] (40) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[StartDate] [datetime] NULL ,
[EndDate] [datetime] NULL ,
[Code] [char] (1) COLLATE SQL_Latin1_General_CP1_CI_AS NULL
) ON [PRIMARY]
GO

Thanks in advance. I'm so appreciative of the help I've gotten here,
as I've been able to write several very useful queries on my own now
after everyones help and plus lots of reading on my own.On 27 Apr 2005 10:54:43 -0700, shumaker@.cs.fsu.edu wrote:

> I'm guessing maybe because it has to do a cartesian product to evaluate
> the WHERE Pkey's equal, then the "SELECT *" just goes ahead and gets
> ALL the fields, and not just those in FooStrings.

Close. The "WHERE EXISTS" is processed such that *no* columns will be
returned by the SELECT * inside it. Instead, it just notes whether any row
was returned and assigns true or false. You could get the same behavior by
replacing SELECT * with SELECT 1, or
SQRT(LEN(FooStringsImport.FooKey))*3.1415926535, or even SELECT NULL.
All of them will do exactly the same thing: completely ignore what comes
after the word SELECT.

Conceptually, the query processor is doing a separate "SELECT *" statement
for each and every row in FooStrings. If that separate statement returns a
row, it deletes the corresponding row from FooStrings; if it doesn't, then
it doesn't.

In actuality, the query optimizer doesn't do that. It rewrites the query as
if it were a JOIN (aka cartesian product, as you stated) and uses that to
decide which rows to delete from FooStringsImport.|||It's called a Correlated Subquery. Theoretically you can assume that the
subquery is executed once for every row in the main (outer) part of the
statement. The correlation part is the reference to the outer table
(FooStringsImport.FooKey). In other words EXISTS returns true for any
particular row in FooStringsImport if there is at least one row in
FooStrings that matches FooStringsImport.FooKey.

This is a Selection operation, not a Join and a DELETE statement rather than
a query, so I don't see that it helps much to think in terms of a Cartesian
Product. In fact SQL Server may use join operations to execute statements
involving subqueries but the server is not going to join every row to every
row before deciding which rows to delete.

See also Joe Celko's narrative on how queries work:
http://www.google.co.uk/groups?selm...ooglegroups.com

By the way, NOT EXISTS is also possible. So rather than do a DELETE followed
by an INSERT why not just filter the INSERT statement in a similar way:

INSERT INTO FooStrings (...)
SELECT ...
FROM FooStringsImport
WHERE NOT EXISTS
(SELECT *
FROM FooStrings
WHERE FooStringsImport.FooKey = FooStrings.FooKey)

--
David Portas
SQL Server MVP
--|||On 27 Apr 2005 10:54:43 -0700, shumaker@.cs.fsu.edu wrote:

>I'm wondering how/why this query works. Trying to get my head wrapped
>around SQL. Basically the Query deletes from the Import table all
>records that are already in FooStrings so that when I do an insert from
>the FooStringsImport table into the FooStrings table, then I won't get
>primary key violations.
>DELETE FROM FooStringsImport
>WHERE EXISTS
>(SELECT * FROM FooStrings
>WHERE FooStringsImport.FooKey = FooStrings.FooKey)
>It seems to work fine, but I'm wondering about how the EXISTS keyword
>works.
>(SELECT * FROM FooStrings
>WHERE FooStringsImport.FooKey = FooStrings.FooKey)
>This part is going to return only records from FooStrings correct? Or
>does it do a cartesian product since I've specified more than one table
>in the WHERE statement?
(snip)

Hi Shumaker,

This is called a correlated subquery. Correlated, because the
"FooStringsImport.FooKey" correlates it to the part of the query outside
the subquery.

The way that this will be executed (in theory - the optimizer usually has
some nifty trcks to get the same result faster, but the slow version is
easier to understand):

- For the DELETE statement, start with the first row of FooStringsImport;
- Replace "FooStringsImport.FooKey" in the subquery with the FooKey value
of that first row;
- Execute the subquery (which now only references the table used in the
FROM clause, making it a stand-alone query);
- Evaluate if the EXISTS predicate is true or false;
- If it is true, delete the first row of FooStringImport; if it's false,
retain it.
- Move to the second row of FooStringsImport;
- Replace "FooStringsImport.FooKey" in the subquery with the FooKey value
of that second row;
- Execute the subquery (which now only references the table used in the
FROM clause, making it a stand-alone query);
- Evaluate if the EXISTS predicate is true or false;
- If it is true, delete the second row of FooStringImport; if it's false,
retain it.
- Move to the third row of FooStringsImport;
(etc etc etc -- until all rows of FooStringImport have been processed).

(Note - the terms "first", "second", etc are used very loosely here, as a
table has no intrinsic order)

The main difference between correlated and non-correlated subqueries, is
that a non-correlated subquery only has to be evaluated once, and the
result set can be retained and reused during the complete query
evaluation, whereas ta correlated subquery has to be recomputed for each
row in the "surrounding" layer of the query.

Best, Hugo
--

(Remove _NO_ and _SPAM_ to get my e-mail address)|||Thanks everyone! This is great info.sql

Friday, March 23, 2012

Non-static data in head of report

Hi everybody,
I'm quite new to reporting services, respectively I were not able zu work
with them for a while, therefore I forget most of the stuff I knew. Here's
my problem:
We have lots of reports made in Microsoft Access, that we now have to
convert for the use in the reporting services (2000). Basically in all
Access reports we use dynamic data in the page header, like a name from an
employee which comes from the database. This seems to be impossible in the
reporting services. We get an error message when compiling the report.
Does anyone know if this possible or a good workaround? I cannot believe
that this isn't possible, it's essential.
Thx in advance
MichaelWe use something like this:
In the hidden text of the body put this
=Code.GetBaseName( First(Fields!BaseState.Value, "DataSet1"))
In the footer/header text use this.
=Code.GetBaseName(Nothing)
Add this to the code pane
' Functions to provide data fields for report header
' Input:
' a data value
' Output:
' data value for report header
' Purpose:
' Provide data values for the report header
' Save data value in a static local variable
' for the last page header, the input variable will be empty
' so return the saved value
' Note:
' The ReportItems passed in must be at the top of the Body of the report
' so they will be accessible on the first page of the report
' The functions are Shared so theStatic variable will work
' The Static variable will retain its value while the report viewer is open,
' even if the parameter values are modified and the report re-run
' so always save the value except when the current value is not available
' All this is necessary because Reporting Services does not allow data
fields in the page header
' and on a Purchase Order with many details, the second page has no detail
fields
' so the hidden data fields cannot not be put in the detail area
public shared function GetBaseName (byval InputValue as string) as string
static SavedValue as string
if InputValue <> "" then
SavedValue = InputValue
return InputValue
else
return SavedValue
end if
end function
Steve MunLeeuw
"Michael Bender" <technik@.salescom.de> wrote in message
news:ecmd6i$c5b$01$1@.news.t-online.com...
> Hi everybody,
> I'm quite new to reporting services, respectively I were not able zu work
> with them for a while, therefore I forget most of the stuff I knew. Here's
> my problem:
> We have lots of reports made in Microsoft Access, that we now have to
> convert for the use in the reporting services (2000). Basically in all
> Access reports we use dynamic data in the page header, like a name from an
> employee which comes from the database. This seems to be impossible in the
> reporting services. We get an error message when compiling the report.
> Does anyone know if this possible or a good workaround? I cannot believe
> that this isn't possible, it's essential.
> Thx in advance
> Michael
>|||Thanks very much, Steve.
"Steve MunLeeuw" <smunson@.clearwire.net> schrieb im Newsbeitrag
news:eDqZMIHyGHA.1936@.TK2MSFTNGP06.phx.gbl...
> We use something like this:
> In the hidden text of the body put this
> =Code.GetBaseName( First(Fields!BaseState.Value, "DataSet1"))
> In the footer/header text use this.
> =Code.GetBaseName(Nothing)
> Add this to the code pane
> ' Functions to provide data fields for report header
> ' Input:
> ' a data value
> ' Output:
> ' data value for report header
> ' Purpose:
> ' Provide data values for the report header
> ' Save data value in a static local variable
> ' for the last page header, the input variable will be empty
> ' so return the saved value
> ' Note:
> ' The ReportItems passed in must be at the top of the Body of the report
> ' so they will be accessible on the first page of the report
> ' The functions are Shared so theStatic variable will work
> ' The Static variable will retain its value while the report viewer is
> open,
> ' even if the parameter values are modified and the report re-run
> ' so always save the value except when the current value is not available
> ' All this is necessary because Reporting Services does not allow data
> fields in the page header
> ' and on a Purchase Order with many details, the second page has no detail
> fields
> ' so the hidden data fields cannot not be put in the detail area
> public shared function GetBaseName (byval InputValue as string) as string
> static SavedValue as string
> if InputValue <> "" then
> SavedValue = InputValue
> return InputValue
> else
> return SavedValue
> end if
> end function
>
> Steve MunLeeuw
> "Michael Bender" <technik@.salescom.de> wrote in message
> news:ecmd6i$c5b$01$1@.news.t-online.com...
>> Hi everybody,
>> I'm quite new to reporting services, respectively I were not able zu work
>> with them for a while, therefore I forget most of the stuff I knew.
>> Here's my problem:
>> We have lots of reports made in Microsoft Access, that we now have to
>> convert for the use in the reporting services (2000). Basically in all
>> Access reports we use dynamic data in the page header, like a name from
>> an employee which comes from the database. This seems to be impossible in
>> the reporting services. We get an error message when compiling the
>> report.
>> Does anyone know if this possible or a good workaround? I cannot believe
>> that this isn't possible, it's essential.
>> Thx in advance
>> Michael
>

Friday, March 9, 2012

NON EMPTY issue

Apologies if this is a bit simple but it's doing my head in a bit

Why would the following MDX return 4 correct records

Code Snippet

SELECT { [Measures].[Signed Surface Area], [Measures].[Amount Signed] } ON COLUMNS ,

non empty{ DESCENDANTS( [Property].[Customer].[All Property], [Property].[Customer].[Customer] ) } ON ROWS

FROM [Lease]

WHERE ( [Time Calcs].[YTD],[Time].[Year].&[2007].&[2].&[5], [Currency].&[26], [Unit of Measure].&[2] )

however adding another measure returns 50 additional spurious measures, all with blank rows

Code Snippet

SELECT NON EMPTY { [Measures].[Signed Leases], [Measures].[Signed Surface Area], [Measures].[Amount Signed] } ON COLUMNS ,

NON EMPTY { DESCENDANTS( [Property].[Customer].[All Property], [Property].[Customer].[Customer] ) } ON ROWS

FROM [Lease]

WHERE ( [Time].[Year].&[2007].&[2].&[5], [Currency].&[26], [Time Calcs].[YTD], [Unit of Measure].&[2] )

The "signed leases" measure was the field added

Presumably you mean that adding the Signed Leases measure returns another 50 spurious rows, not measures? Is Signed Leases a calculated measure, and if so what is its definition? I'm guessing [Time Calcs].[YTD] is another calculated measure (and is probably the culprit) - what is its definition? Have you been using the Non_Empty_Behavior property anywhere?

Chris

|||

Chris,

Yes, you were correct in your assumption. TimeCalcs was OK, it was actually the fact that signed leases was calculated. Adding an iif statement to create a null sorted it