From: Benjamin Kalytta on
Hello Mr. Ratchev,

> Here is a query that works in SQL CE:
> [...]

Thank you for that, it really works. I even understand your query, don't
know why I wasn't able to find it by my self.

However my real query will be a bit more complex because there is not
only one metric to compare, but several metrics. This compareable
metrics are stored in another table which will be referenced by their
MAC Address:

JOIN DeviceTable C ON (C.Id = A.DeviceId AND (C.MacAddress =
0x1234567890ab OR C.MacAddress = ... OR ...)) ...

I don't know if it is better to use UNIONS here or to make your query a
bit more complex if that even works:

SELECT A.RouterId, A.DeviceId, A.Metric
FROM LinkTable AS A
JOIN DeviceTable AS C ON (C.Id = A.DeviceId AND (C.MacAddress =
0x1234567890ab OR C.MacAddress = ... OR ...))
JOIN (SELECT RouterId, DeviceId, MIN(ABS(C.Metric - Metric)) AS min_metric
FROM LinkTable
GROUP BY RouterId, DeviceId) AS B
ON B.DeviceId = A.DeviceId
AND B.RouterId = A.RouterId
AND ABS(C.Metric - A.Metric) = min_metric;

But that should work isn't it?

Regards,
Benjamin Kalytta
From: Plamen Ratchev on
This should work, no need for UNION. You can use IN instead of ORs, C.MacAddress IN (...).

--
Plamen Ratchev
http://www.SQLStudio.com
From: Erland Sommarskog on
Benjamin Kalytta (bkausbk(a)web.de) writes:
> unfortunately it doesn't work as expected. SQL CE says, it can't find
> column C.Metric
>
> SELECT A.RouterId, A.DeviceId, A.Metric
> FROM LinkTable AS A
> JOIN DeviceTable AS C ON (C.Id = A.DeviceId AND (C.MacAddress =
> 0x1234567890ab OR C.MacAddress = ... OR ...))
> JOIN (SELECT RouterId, DeviceId, MIN(ABS(C.Metric - Metric)) AS min_metric
> FROM LinkTable
> GROUP BY RouterId, DeviceId) AS B
> ON B.DeviceId = A.DeviceId
> AND B.RouterId = A.RouterId
> AND ABS(C.Metric - A.Metric) = min_metric;

No, that query would not work on real SQL Server either.

Let's go back to Plamen's query:

SELECT A.RouterId, A.DeviceId, A.Metric
FROM Foo AS A
JOIN (SELECT RouterId, DeviceId, MIN(ABS(90 - Metric)) AS min_metric
FROM Foo
GROUP BY RouterId, DeviceId) AS B
ON B.DeviceId = A.DeviceId
AND B.RouterId = A.RouterId
AND ABS(90 - A.Metric) = min_metric;

The thing in parenthesis is a *derived table*. Logically, it is a
temp table within the table, but it is not materialised, and the
actual computation order by be different, at least on SQL Server.

The derived table produces the (RouterId, DeviceId) that is closest to
the metric, and then we join back to the whole table to get further
data. Note, by the way, that the query can return more than one row for
the same (RouterId, DeviceID), for instance if you have one tuple with
Metric = 95 and one with Metric = 105.

And important property of a derived table is that it is blind for
tables outside it, why you cannot refer to DeviceTable it. Keep in
mind, that logically the derived table is computed first.

Looking at your query it seems to me that you need the DeviceTable
in two places:

SELECT LT1.RouterId, LT1.DeviceId, LT1.Metric
FROM LinkTable AS LT1
JOIN DeviceTable AS DT1 ON DT1.Id = LT1.DeviceId
AND DT1.MacAddress IN (0x1234567890ab, ...)
JOIN (SELECT LT2.RouterId, LT2.DeviceId,
MIN(ABS(DT2.Metric - LT2.Metric)) AS min_metric
FROM LinkTable LT2
JOIN DeviceTable AS DT2 ON DT2.Id = LT2.DeviceId
AND DT2.MacAddress IN (0x1234567890ab, ...)
GROUP BY LT2.RouterId, LT2.DeviceId) AS LT2
ON LT1.DeviceId = LT2.DeviceId
AND LT1.RouterId = LT2.RouterId
AND ABS(DT1.Metric - LT1.Metric) = LT2.min_metric;


Disclaimer: I have never worked with Compact Edition, and I can't
vouch for that Compact will be able ro run this query.
--
Erland Sommarskog, SQL Server MVP, esquel(a)sommarskog.se

Links for SQL Server Books Online:
SQL 2008: http://msdn.microsoft.com/en-us/sqlserver/cc514207.aspx
SQL 2005: http://msdn.microsoft.com/en-us/sqlserver/bb895970.aspx
SQL 2000: http://www.microsoft.com/sql/prodinfo/previousversions/books.mspx

From: Erland Sommarskog on
Benjamin Kalytta (bkausbk(a)web.de) writes:
> OK, but now the Question is (if this would work in Compact Edition),
> would it make sense to make such a complex query? May be it is better to
> put some logic outside of the query into the main application?

As I don't know your application, and nor do I have any knowledge of
SQL Server Compact Edition, I cannot give you answer.

But had you been working in "real" SQL Server, my answer would have been
"probably not". (If you think that is a complex query, you should see some
of those I write at work. :-)

--
Erland Sommarskog, SQL Server MVP, esquel(a)sommarskog.se

Links for SQL Server Books Online:
SQL 2008: http://msdn.microsoft.com/en-us/sqlserver/cc514207.aspx
SQL 2005: http://msdn.microsoft.com/en-us/sqlserver/bb895970.aspx
SQL 2000: http://www.microsoft.com/sql/prodinfo/previousversions/books.mspx