Search code examples
graphgraph-databasessql-server-2017sql-graphsql-server-2017-graph

Use views and table valued functions as node or edge tables in match clauses


I like to use Table Valued functions in MATCH clauses in the same way as is possible with Node tables. Is there a way to achieve this?

The need for table valued functions

There can be various use cases for using table valued functions or views as Node tables. For instance mine is the following.
I have Node tables that contain NVarChar(max) fields that I would like to search for literal text. I need only equality searching and no full text searching, so I opted for using a index on the hash value of the text field. As suggested by Remus Rusanu in his answer to SQL server - worth indexing large string keys? and https://www.brentozar.com/archive/2013/05/indexing-wide-keys-in-sql-server/. A table valued function handles using the CHECKSUM index; see Msg 207 Invalid column name $node_id for pseudo column in inline table valued function.

Example data definitions

CREATE TABLE [Tags](
    [tag] NVarChar(max),
    [tagHash] AS CHECKSUM([Tag]) PERSISTED NOT NULL
) as Node;

CREATE TABLE [Sites](
    [endPoint] NVarChar(max),
    [endPointHash] AS CHECKSUM([endPoint]) PERSISTED NOT NULL
) as Node;

CREATE TABLE [Links] as Edge;

CREATE INDEX [IX_TagsByName] ON [Tags]([tagHash]);

GO

CREATE FUNCTION [TagsByName](
    @tag NVarChar(max))
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN SELECT
    $node_id AS [NodeId],
    [tag],
    [tagHash]
FROM [dbo].[Tags]
WHERE [tagHash] = CHECKSUM(@tag) AND
    [tag] = @tag;

[TagsByName] returns the $node_id with an alias NodeId as suggested by https://stackoverflow.com/a/45565410/814206. However, real Node tables contain two more internal columns which I do not know how to export.

Desired query

I would like to query the database similar to this:

SELECT *
FROM [TagsByName]('important') as t,
    [Sites] as s,
    [Links] as l
WHERE MATCH ([t]-([l])->[s])

However, this results in the error1:

Msg 13901, Level 16, State 2, Line ...
Identifier 't' in a MATCH clause is not a node table or an alias for a node table.

I there a way to do this?


PS. There are some workarounds but they do not look as elegant as the MATCH-query; especially considering that my actual query involves matching more relations and more string equality tests. I will post these workarounds as answers and hope that someone comes with a better idea.

1 This gives a very specific difference between views and tables for Difference between View and table in sql; which only occurs in and only when using SQL Graph.


Solution

  • Workaround

    Add the Node table twice to the from clause: once as table and once as table valued function and join them via the $node_id in the where clause:

    SELECT *
    FROM [TagsByName]('important') as t1,
        [Tags] as t2,
        [Sites] as s,
        [Links] as l
    WHERE MATCH ([t2]-([l])->[s]) AND
        t1.[NodeId] = t2.$node_id
    

    Does this affect performance?