简体   繁体   中英

SQL Query For Graph Like Table

Graph can be represented using vertex and edge table .

Vertex holds nodes details and edge holds the relationship .

    VERTEX                        EDGE
    ------                       ----------------------------
     ID                           ID    |  Source   | Target
    ------                       ----------------------------
     A                            1        A            B
     B                            2        A            B
     C                            3        B            C
     D                            4        B            D
     E                            5        D            B
                                  6        A            D
                                  7        B            A
                                  8        E            A

Graph :

在此输入图像描述

I am trying to get direct neighbor of each node using SQL query .

 OUTPUT
---------------------------
ID    | COUNT
---------------------------
 A        3
 B        3
 C        1
 D        2
 E        1

Explanation :

A has connection to E , D , B

B has connection to C, A, D

To add this variant:

select source, count(distinct target) 
from
    (select  source, target 
    from edge e_out
    union all
    select  target, source -- note the switch of src/trgt columns
    from edge e_in)
group by source
order by source;

Please check following SQL query giving the exact result you are looking for

select
    Vertex.ID,
    Count(Neighbour) as "Count"
from GraphVertex as Vertex
left join (
select
    v.ID,
    e.Target as Neighbour
from GraphVertex as v
inner join GraphEdge as e
    on v.ID = e.Source

union

select
    v.ID,
    e.Source as Neighbour
from GraphVertex as v
inner join GraphEdge as e
    on v.ID = e.Target
) as Neighbours
    on Vertex.ID = Neighbours.ID
group by Vertex.ID
order by Vertex.ID;

although you have named your tables as Vertex and Edge all solutions provided here seem to be SQLScript solutions instead of a Graph language solution.

I tried to create a Graph database solution for your request, but I had a few difficulties that I had to overcome.

First, since I am new to Graph I could not find a direct solution. You know Edge's are directed records. But your question wants total number of neighbors in both directions. So I had to dublicate the rows by cross-changing the source and target columns.

Then I used following procedure

CREATE PROCEDURE graphProcedureSample2(in ID varchar(2), out cnt int)
LANGUAGE GRAPH READS SQL DATA AS
BEGIN
    Graph g = Graph("A00077387", "SAMPLEGRAPHWORKSPACE");
    cnt = 0;
    Vertex v = Vertex(:g, :ID);
    Multiset<Vertex> neighbors = NEIGHBORS (:g, :v, 1, 1);
    Multiset<Edge> edges = EDGES (:g, :v, :neighbors);
    cnt = INT(COUNT(:neighbors));
END;

But above code works only for a single vertex.

在此输入图像描述

I had to create HANA database cursor and loop through all vertices then call this SP for each.

I have stored the results in a temp table and got the result you requested by querying this temp table.

I hope it helps,

select a, count(*) as connections from
(
    select a, b from
    (
        select Source a, Target b from EDGE
        union
        select Target a, Source b from EDGE
    ) group by a,b
) group by a

You can use the following query:

SELECT CASE WHEN Source < Target THEN Source ELSE Target END AS Node1,
       CASE WHEN Source >= Target THEN Source ELSE Target END AS Node2
FROM EDGE

to get:

Node1   Node2
-------------
A       B
A       B
B       C
B       D
B       D
A       D
A       B
A       E

This is a simplified, stripped down, version of the EDGE table, that contains only node connection information.

You can further strip down using DISTINCT :

SELECT DISTINCT
       CASE WHEN Source < Target THEN Source ELSE Target END AS Node1,
       CASE WHEN Source >= Target THEN Source ELSE Target END AS Node2
FROM EDGE

so that duplicates are removed:

Node1   Node2
-------------
A       B
A       D
A       E
B       C
B       D

You can now wrap the above query in a CTE , unpivot and then count:

;WITH SimpleEDGE AS (
    SELECT DISTINCT
           CASE WHEN Source < Target THEN Source ELSE Target END AS Node1,
           CASE WHEN Source >= Target THEN Source ELSE Target END AS Node2
    FROM EDGE
)
SELECT Node, COUNT(*) AS cnt
FROM (
    SELECT Node1 AS Node
    FROM SimpleEDGE

    UNION ALL

    SELECT Node2 AS Node
    FROM SimpleEDGE
) AS t
GROUP BY Node

Output:

Node    cnt
-----------
A       3
B       3
C       1
D       2
E       1

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM