all groups > sql server programming > march 2005 >
You're in the

sql server programming

group:

SQL: A problematic exists query (again)


SQL: A problematic exists query (again) mawi
3/29/2005 10:46:13 PM
sql server programming:
Hello,

I've tinkered with this problem but have not found a solution.

(There is setup SQL below and my problem query)

*** Structure: Nodes transferring units. One nodes table.
It is related to itself, so that a nodes can supply another
node.
This relation (xfers) also has a volume, how much has each
node supplied the next with. Each node processes intervals
(of units).

.-----.
|xfers|----+
`-----' |
| |
| .--+--. 1.* .---------.
|-----+nodes|--------.intervals|
`-----' `---------'

*** Problem: I want to formulate a query that returns all
nodes, all sourcenodes of every node and one matching
interval for each sourcenode. I want to be able to sum up
the sourcenodes (xfers) transfer volumes correctly.

The problem is that the apparent query (example B) will (of
course) give me all sourcenodes and all matching intervals,
which may be more than one per sourcenode. This is not
interesting information, although correct. In the example:
Node 57 has node 25 as source. Node 25 has two intervals
that match node 57 intervals. I get two rows in the
resultset for the 57-25 relation (two transfer volumes
"3"). Correct per se, but now what I am after.

The desired rows are one for each sourcenode, and first
interval match. Example A satisfies the first condition but
does not let me display data from the first interval match.

Any help greatly appreciated.

/mawi

Correct rows, but not all columns:

nodeid nodename source_nodeid volume
------- ---------- ------------- -------
12 Run A NULL NULL
25 Switch A B NULL NULL
26 Continue B NULL NULL
57 Mix 12 15
57 Mix 25 3
57 Mix 26 28

Incorrect rows but some of the desired columns:

nodeid nodename source_nodeid volume start stop
------ ---------- ------------- ------ ----- -----
12 Run A NULL NULL NULL NULL
25 Switch A B NULL NULL NULL NULL
26 Continue B NULL NULL NULL NULL
57 Mix 12 15 1 180
57 Mix 25 3 181 195
57 Mix 25 3 1 21
57 Mix 26 28 22 492

Code is also here, setup:
http://authors.aspalliance.com/aylar/ViewPasteCode.aspx?PasteCodeID=4019
Problem queries:
http://authors.aspalliance.com/aylar/ViewPasteCode.aspx?PasteCodeID=4020

**** SQL CODE, setup:
-- mawi T-SQL EXISTS to JOIN problem: Setup script
create database IntervalXfers
go
use IntervalXfers
go

CREATE TABLE nodes ( nodeid INT, nodename VARCHAR(32),
PRIMARY KEY( nodeid ) )
CREATE TABLE xfers ( target_nodeid INT, source_nodeid INT,
volume INT, PRIMARY KEY( source_nodeid, target_nodeid ) )
CREATE TABLE intervals ( nodes_nodeid INT, lot VARCHAR(3),
lotcount INT, start INT, stop INT, PRIMARY KEY(
nodes_nodeid, lot, lotcount ) )
go

INSERT INTO nodes
SELECT 12, 'Run A' UNION
SELECT 25, 'Switch A B' UNION
SELECT 26, 'Continue B' UNION
SELECT 57, 'Mix'
go
INSERT INTO intervals
SELECT 12, 'A', 1, 1, 180 UNION
SELECT 25, 'A', 1, 181, 195 UNION
SELECT 25, 'B', 1, 1, 21 UNION
SELECT 26, 'B', 1, 22, 492 UNION
SELECT 57, 'A', 1, 1, 195 UNION
SELECT 57, 'B', 1, 1, 492
go
INSERT INTO xfers
SELECT 57, 12, 15 UNION
SELECT 57, 25, 3 UNION
SELECT 57, 26, 28
go
CREATE FUNCTION Intersection ( @startA int, @stopA int,
@startB int, @stopB int )
RETURNS bit
AS
BEGIN
DECLARE @rValue bit
IF
@startA BETWEEN @startB AND @stopB
OR
@stopA BETWEEN @startB AND @stopB
SET @rValue = 1
ELSE
SET @rValue = 0

RETURN ( @rValue )
END
go


*** SQL CODE PROBLEMS:
-- Desired rows, yet I cannot access the matching row in
the EXISTS test
SELECT
nodes.nodeid, nodes.nodename,
source_nodeid, volume
FROM nodes
LEFT OUTER JOIN xfers
ON target_nodeid = nodes.nodeid AND EXISTS
( SELECT *
FROM intervals sourceIntervals
JOIN intervals nodeIntervals
ON
nodeIntervals.lot = sourceIntervals.lot
AND dbo.Intersection( nodeIntervals.start,
nodeIntervals.stop, sourceIntervals.start,
sourceIntervals.stop ) = 1
WHERE
sourceIntervals.nodes_nodeid = xfers.source_nodeid
AND nodeIntervals.nodes_nodeid = xfers.target_nodeid
)
LEFT OUTER JOIN nodes sourceNodes
ON sourceNodes.nodeid = source_nodeid

-- Test with join, one of many, not correct
SELECT
nodes.nodeid, nodes.nodename,
source_nodeid, volume, sourceIntervals.start,
sourceIntervals.stop
FROM nodes
LEFT OUTER JOIN
xfers
LEFT OUTER JOIN intervals sourceIntervals
ON sourceIntervals.nodes_nodeid = xfers.source_nodeid
JOIN intervals nodeIntervals
ON
nodeIntervals.nodes_nodeid = xfers.target_nodeid
AND nodeIntervals.lot = sourceIntervals.lot
AND dbo.Intersection( nodeIntervals.start,
nodeIntervals.stop, sourceIntervals.start,
sourceIntervals.stop ) = 1
ON target_nodeid = nodes.nodeid
LEFT OUTER JOIN nodes sourceNodes
ON sourceNodes.nodeid = source_nodeid
Re: SQL: A problematic exists query (again) Carl Federl
3/30/2005 8:57:52 AM
The difficulty is in determining what is meant by "first
interval match" This SQL uses the lowest values for
the target interval lot and lotcount and the corresponding lowest values
for the source interval lot and lot count. This is done by converting
the lot and lotcount to fixed length characters (with spaces replacing
nulls), then concatenating the 4 column values and finally specifying
the minimum. The concatenated column is then take back apart and
converted to the original datatypes and joined to the base tables to get
the non-key columns.

SELECT TargetNodes.nodeid
, TargetNodes.nodename
, SourceNodes.nodeid
, SourceNodes.nodename
, xfers.volume
, SourceIntervals.lot
, SourceIntervals.lotcount
, SourceIntervals.start
, SourceIntervals.stop
, TargetIntervals.lot
, TargetIntervals.lotcount
, TargetIntervals.start
, TargetIntervals.stop
FROM (
SELECT TargetNodes.nodeid
, SourceNodes.nodeid
, xfers.volume
, MIN ( COALESCE( CAST( SourceIntervals.lot as char(3)) , '' )
+ COALESCE( CAST( SourceIntervals.lotcount as char(12)) , '')
+ COALESCE( CAST( TargetIntervals.lot as char(3)) , '' )
+ COALESCE( CAST( TargetIntervals.lotcount as char(12)), '' ))
FROM nodes AS TargetNodes
JOIN intervals TargetIntervals
on TargetIntervals.nodes_nodeid = TargetNodes.nodeid
LEFT OUTER JOIN xfers
ON xfers.target_nodeid = TargetNodes.nodeid
LEFT OUTER JOIN nodes AS SourceNodes
ON SourceNodes.nodeid = xfers.source_nodeid
JOIN intervals sourceIntervals
on sourceIntervals.nodes_nodeid = xfers.source_nodeid
where ( TargetIntervals.start between sourceIntervals.start and
sourceIntervals.stop
OR TargetIntervals.stop between sourceIntervals.start and
sourceIntervals.stop
)
group by TargetNodes.nodeid
, SourceNodes.nodeid
, xfers.volume
) as IntervalsMin (TargetNodes_nodeid, SourceNodes_nodeid, volume
, Intervals_K )
JOIN nodes AS TargetNodes
ON TargetNodes.nodeid = IntervalsMin.TargetNodes_nodeid
LEFT OUTER JOIN nodes AS SourceNodes
ON SourceNodes.nodeid = IntervalsMin.SourceNodes_nodeid
LEFT OUTER JOIN xfers
ON xfers.target_nodeid = TargetNodes.nodeid
and xfers.source_nodeid = IntervalsMin.SourceNodes_nodeid
LEFT OUTER JOIN intervals sourceIntervals
ON SourceIntervals.nodes_nodeid = IntervalsMin.SourceNodes_nodeid
and SourceIntervals.lot = SUBSTRING( Intervals_K, 1, 3)
AND SourceIntervals.lotcount = cast( SUBSTRING( Intervals_K, 4, 12) AS
INTEGER)
LEFT OUTER JOIN intervals TargetIntervals
ON TargetIntervals.nodes_nodeid = IntervalsMin.TargetNodes_nodeid
and TargetIntervals.lot = SUBSTRING( Intervals_K , 16, 3)
AND TargetIntervals.lotcount = cast( SUBSTRING( Intervals_K , 19, 12)
AS INTEGER)



Re: SQL: A problematic exists query (again) mawi
3/30/2005 11:20:25 PM
Hi Carl!

Wow, great! I will have to look at what you are doing in
more detail by this weekend.

Thanks alot!

Best regards,

AddThis Social Bookmark Button