I have an Orient database with vertices for servers from different management tools. As a server can be monitored by multiple management tools, I would like to create edges between the vertices for the same server. The connected components would then be the individual servers.
The problem I have, is that different systems will have different naming conventions - some use fully qualified domain names, some use internal domain names, and some only use the hostname.
My Sample Data:
orientdb {db=audit}> select * from V
+----+------+-------+----------+----------------------+----------------+
|# |#RID |#CLASS |Name |DomainName |LocalName |
+----+------+-------+----------+----------------------+----------------+
|0 |#12:0 |Alpha |compute-1 |null |null |
|1 |#12:1 |Alpha |compute-2 |null |null |
|2 |#12:2 |Alpha |compute-3 |null |null |
|3 |#13:0 |Beta |null |compute-1.example.com |null |
|4 |#13:1 |Beta |null |compute-2.example.com |null |
|5 |#14:0 |Gamma |null |null |compute-1.local |
|6 |#14:1 |Gamma |null |null |compute-3.local |
+----+------+-------+----------+----------------------+----------------+
Expected Output:
I would expect 3 distinct commands (pseudocoded below), that would produce the below edges
Alpha to Beta:
Select from Alpha, join Name as a substring of Beta.DomainName
edge between #12:0 and #13:0
edge between #12:1 and #13:1
Alpha to Gamma:
Select from Alpha, join Name & ".local" with Gamma.LocalName
edge between #12:0 and #14:0
edge between #12:2 and #14:1
Beta to Gamma:
Select LocalName from Gamma, remove ".local" suffix, join as a substring of Beta.DomainName
edge between #13:0 and #14:0
Try this JS function:
var db = orient.getGraph();
var a = db.command('sql','select from Alpha');
var b = db.command('sql','select from Beta');
var g = db.command('sql','select from Gamma');
//Alpha to Beta
for(i=0;i<b.length;i++)
{
var name = a[i].getRecord().field('Name');
var Arid = a[i].getRecord().field('#rid');
for(j=0;j<b.length;j++)
{
var dn = b[j].getRecord().field('DomainName').substring(0,name.length);
var Brid = b[j].getRecord().field('#rid');
if(name==dn)
{
db.command('sql','create edge E from '+Arid+' to '+Brid+'');
}
}
}
//Alpha to Gamma
for(i=0;i<a.length;i++)
{
var name = a[i].getRecord().field('Name');
var Arid = a[i].getRecord().field('#rid');
for(j=0;j<g.length;j++)
{
var ln = g[j].getRecord().field('LocalName').substring(0,name.length);
var Grid = g[j].getRecord().field('#rid');
if(name==ln)
{
db.command('sql','create edge E from '+Arid+' to '+Grid+'');
}
}
}
//Beta to Gamma
for(i=0;i<b.length;i++)
{
var name = b[i].getRecord().field('DomainName').substring(0,9);
var Brid = b[i].getRecord().field('#rid');
for(j=0;j<g.length;j++)
{
var n = g[j].getRecord().field('LocalName').substring(0,name.length);
var Grid = g[j].getRecord().field('#rid');
if(name==n)
{
db.command('sql','create edge E from '+Brid+' to '+Grid+'');
}
}
}
This is the output:
Hope it helps.
Regards
You can use these queries :
create edge from (select from Alpha where Name="compute-1") to (select from Beta where DomainName like "compute-1%")
create edge from (select from Alpha where Name="compute-2") to (select from Beta where DomainName like "compute-2%")
create edge from (select from Alpha where Name="compute-1") to (select from Gamma where LocalName like "compute-1%")
create edge from (select from Alpha where Name="compute-3") to (select from Gamma where LocalName like "compute-3%")
create edge from (select from Beta where DomainName like "compute-1%") to (select from Gamma where LocalName like "compute-1%")
Hope it helps
Related
How is the result of %ROWCOUNT displayed in the SQL statement.
Example
Select top 10 * from myTable.
I would like the results to have a rowCount for each row returned in the result set
Ex
+----------+--------+---------+
|rowNumber |Column1 |Column2 |
+----------+--------+---------+
|1 |A |B |
|2 |C |D |
+----------+--------+---------+
There are no any simple way to do it. You can add Sql Procedure with this functionality and use it in your SQL statements.
For example, class:
Class Sample.Utils Extends %RegisteredObject
{
ClassMethod RowNumber(Args...) As %Integer [ SqlProc, SqlName = "ROW_NUMBER" ]
{
quit $increment(%rownumber)
}
}
and then, you can use it in this way:
SELECT TOP 10 Sample.ROW_NUMBER(id) rowNumber, id,name,dob
FROM sample.person
ORDER BY ID desc
You will get something like below
+-----------+-------+-------------------+-----------+
|rowNumber |ID |Name |DOB |
+-----------+-------+-------------------+-----------+
|1 |200 |Quigley,Neil I. |12/25/1999 |
|2 |199 |Zevon,Imelda U. |04/22/1955 |
|3 |198 |O'Brien,Frances I. |12/03/1944 |
|4 |197 |Avery,Bart K. |08/20/1933 |
|5 |196 |Ingleman,Angelo F. |04/14/1958 |
|6 |195 |Quilty,Frances O. |09/12/2012 |
|7 |194 |Avery,Susan N. |05/09/1935 |
|8 |193 |Hanson,Violet L. |05/01/1973 |
|9 |192 |Zemaitis,Andrew H. |03/07/1924 |
|10 |191 |Presley,Liza N. |12/27/1978 |
+-----------+-------+-------------------+-----------+
If you are willing to rewrite your query then you can use a view counter to do what you are looking for. Here is a link to the docs.
The short version is you move your query into a FROM clause sub query and use the special field %vid.
SELECT v.%vid AS Row_Counter, Name
FROM (SELECT TOP 10 Name FROM Sample.Person ORDER BY Name) v
Row_Counter Name
1 Adam,Thelma P.
2 Adam,Usha J.
3 Adams,Milhouse A.
4 Allen,Xavier O.
5 Avery,James R.
6 Avery,Kyra G.
7 Bach,Ted J.
8 Bachman,Brian R.
9 Basile,Angelo T.
10 Basile,Chad L.
I need to generate a sequence starting from a CSV string and a maximum count.
When the sequence exceed, I need to start the sequence again and continue until I saturate the COUNT variable
I have the following CSV:
A,B,C,D
In order to get 4 rows out of this CSV I am using XML and the following statement:
SET #xml_csv = N'<root><r>' + replace('A, B, C, D',',','</r><r>') + '</r></root>'
SELECT
REPLACE(t.value('.','varchar(max)'), ' ', '') AS [delimited items]
FROM
#xml_csv.nodes('//root/r') AS a(t)
Now my SELECT returns the following output:
|-------------|
| A |
| B |
| C |
| D |
Assuming I have a #count variable set to 9, I need to output the following:
|--|-----------|
|1 |A |
|2 |B |
|3 |C |
|4 |D |
|5 |A |
|6 |B |
|7 |C |
|8 |D |
|9 |A |
I tried to join a table called master..[spt_values] but I get for a COUNT = 10 10 rows for A, 10 for B and so on, while I need the sequence ordered and repeated until it saturate
Basically you are on the correct path. Joining the split result with a numbers table will get you the correct output.
I've chosen to use a different function for splitting the csv data since it's using a numbers table for the split as well. (taken from this great article)
First, if you don't already have a numbers table, create one. here is the script used in the article I've linked to:
SET NOCOUNT ON;
DECLARE #UpperLimit INT = 1000;
WITH n AS
(
SELECT
x = ROW_NUMBER() OVER (ORDER BY s1.[object_id])
FROM sys.all_objects AS s1
CROSS JOIN sys.all_objects AS s2
CROSS JOIN sys.all_objects AS s3
)
SELECT Number = x
INTO dbo.Numbers
FROM n
WHERE x BETWEEN 1 AND #UpperLimit;
GO
CREATE UNIQUE CLUSTERED INDEX n ON dbo.Numbers(Number)
WITH (DATA_COMPRESSION = PAGE);
GO
Then, create the split function:
CREATE FUNCTION dbo.SplitStrings_Numbers
(
#List NVARCHAR(MAX),
#Delimiter NVARCHAR(255)
)
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN
(
SELECT Item = SUBSTRING(#List, Number,
CHARINDEX(#Delimiter, #List + #Delimiter, Number) - Number)
FROM dbo.Numbers
WHERE Number <= CONVERT(INT, LEN(#List))
AND SUBSTRING(#Delimiter + #List, Number, LEN(#Delimiter)) = #Delimiter
);
GO
Next step: Join the split results with the numbers table:
DECLARE #Csv varchar(20) = 'A,B,C,D'
SELECT TOP 10 Item
FROM dbo.SplitStrings_Numbers(#Csv, ',')
CROSS JOIN Numbers
ORDER BY Number
Output:
Item
----
A
B
C
D
A
B
C
D
A
B
Great thanks to Aaron Bertrand for sharing his knowledge.
I want to update some rows of my table basing on other rows of the same table:
I try this:
UPDATE MyTable set myField =
(SELECT T1.myField
FROM MyTable T1
WHERE T1.id.substring(start,stop) = MyTable.id.substring(start,stop))
But OrientDB throws an error like this:
com.orientechnologies.orient.core.sql.OCommandSQLParsingException: Error on parsing command at position #XXX: Invalid keyword 'T1' Command:
first of all you in OrientDB you can't use Alias on Classes.
In this case you could use $parent.$current in a subquery, something like:
> update MyTable set myField = (
> select myField
> from MyTable
> where myField is null
> and id.substring(8,13) = $parent.$current.id.substring(8,13) and something else...
> ) where myField is null and something else...
Be careful to the length of the id...
Best Regards
M.
This is not a string update, but an integer update in place. Using the provided GratefulDeadDatabase, you can do:
CONNECT remote:localhost/GratefulDeadConcerts;
SELECT performances FROM v;
----+------+------------
# |#CLASS|performances
----+------+------------
0 |null |null
1 |null |5
2 |null |1
3 |null |531
4 |null |394
----+------+------------
UPDATE v SET performances = eval('performances + 2') WHERE performances IS NOT NULL;
SELECT performances FROM v;
----+------+------------
# |#CLASS|performances
----+------+------------
0 |null |null
1 |null |7
2 |null |3
3 |null |533
4 |null |396
----+------+------------
So the update works on the data in place. I'm fairly new to OrientDB so maybe an expert can tell me if I just did something horribly horribly wrong.
UPDATE
Notice that in your example you are updating the table with values from the same table. That is, from MyTable into MyTable (unless I misunderstood your query) and even within the same row. You can use criteria on the WHERE clause to only update rows of interest. In my example, that was
WHERE performances IS NOT NULL
I want to select all vertices that are connected to another vertex. I am currently using the traverse function in OrientDB. Consider the following example:
> create class professor extends V
> create class course extends V
> insert into professor set name='Smith'
Inserted record 'professor#14:0{name:Smith} v1'
> insert into course set name='Calculus'
Inserted record 'course#15:0{name:Calculus} v1'
> create class teaches extends E
> create edge teaches from #14:0 to #15:0
Created edge '[teaches#16:0{out:#14:0,in:#15:0} v3]'
Now when I try to traverse to find the course(s) that professor Smith teaches I use the following command:
> traverse out_teaches from #15:0
----+-----+---------+-----+-----------+-----+-----
# |#RID |#CLASS |name |out_teaches|out |in
----+-----+---------+-----+-----------+-----+-----
0 |#14:0|professor|Smith|[size=1] |null |null
1 |#16:0|teaches |null |null |#14:0|#15:0
----+-----+---------+-----+-----------+-----+-----
Why does this return to me the edge and not the vertex (course) that I am looking for? What is the appropriate command to return to me the vertex? I want the record for 'Calculus' to be returned.
I expanded your graph a bit to try your query.
If you want to know only the connected vertices to some starting vertex by the edge 'teaches' you should use SELECT EXPAND (OUT / IN / BOTH) because TRAVERSE is more useful if you wish to explore the graph at different depths (in my case "Smith" has the #rid #11:0):
select expand(out('teaches')) from (select from Professor where name='Smith')
----+-----+------+------------+----------+----------
# |#RID |#CLASS|name |in_teaches|in_follows
----+-----+------+------------+----------+----------
0 |#12:0|course|Calculus |[size=1] |[size=1]
1 |#12:1|course|Astrophysics|[size=1] |[size=1]
2 |#12:2|course|Law |[size=2] |[size=1]
----+-----+------+------------+----------+----------
or with select expand(out('teaches')) from #11:0 you will obtain the same result:
----+-----+------+------------+----------+----------
# |#RID |#CLASS|name |in_teaches|in_follows
----+-----+------+------------+----------+----------
0 |#12:0|course|Calculus |[size=1] |[size=1]
1 |#12:1|course|Astrophysics|[size=1] |[size=1]
2 |#12:2|course|Law |[size=2] |[size=1]
----+-----+------+------------+----------+----------
or you can obtain all the connected vertices to the professor "Smith"
select expand(out()) from professor where name="Smith"
----+-----+----------+------------+----------+----------+------------+----------
# |#RID |#CLASS |name |in_teaches|in_follows|in_studiesAt|in_worksAt
----+-----+----------+------------+----------+----------+------------+----------
0 |#12:0|course |Calculus |[size=1] |[size=1] |null |null
1 |#12:1|course |Astrophysics|[size=1] |[size=1] |null |null
2 |#12:2|course |Law |[size=2] |[size=1] |null |null
3 |#16:0|university|Cambridge |null |null |[size=1] |[size=1]
----+-----+----------+------------+----------+----------+------------+----------
Your query traverse out_teaches from #11:0 seems to list the starting vertex and all of the connected edges with relative IN and OUT vertices:
----+-----+---------+-----+-----------+-----------+-----+-----
# |#RID |#CLASS |name |out_teaches|out_worksAt|out |in
----+-----+---------+-----+-----------+-----------+-----+-----
0 |#11:0|professor|Smith|[size=3] |[size=1] |null |null
1 |#13:0|teaches |null |null |null |#11:0|#12:0
2 |#13:1|teaches |null |null |null |#11:0|#12:1
3 |#13:2|teaches |null |null |null |#11:0|#12:2
----+-----+---------+-----+-----------+-----------+-----+-----
I tried also traverse out_teaches from professor and the result is similar to the previous query:
----+-----+---------+-----+-----------+-----------+-----+-----
# |#RID |#CLASS |name |out_teaches|out_worksAt|out |in
----+-----+---------+-----+-----------+-----------+-----+-----
0 |#11:0|professor|Smith|[size=3] |[size=1] |null |null
1 |#13:0|teaches |null |null |null |#11:0|#12:0
2 |#13:1|teaches |null |null |null |#11:0|#12:1
3 |#13:2|teaches |null |null |null |#11:0|#12:2
4 |#11:1|professor|Green|[size=1] |[size=1] |null |null
5 |#13:3|teaches |null |null |null |#11:1|#12:2
----+-----+---------+-----+-----------+-----------+-----+-----
The correct syntax for selecting the courses (at least in OrientDB 2.1) would be based on out('teaches'). For example:
> select expand(out('teaches')) from (select from Professor where name='Smith')
----+-----+------+--------+----------
# |#RID |#CLASS|name |in_teaches
----+-----+------+--------+----------
0 |#12:0|Course|Calculus|[size=1]
----+-----+------+--------+----------
That is, there's just one vertex, as expected.
Please note that 'traverse' is used for a different purpose. It involves an iterative procedure for traversing graphs.
out_teaches
"out_teaches" is a reference to an edge. Using OrientDB 2.1.7, the response I obtained for your "out_teaches" query is as follows:
> select expand(out_teaches) from (select from Professor where name='Smith')
----+-----+-------+-----+-----
# |#RID |#CLASS |out |in
----+-----+-------+-----+-----
0 |#13:0|teaches|#11:0|#12:0
----+-----+-------+-----+-----
Again, this is what one would expect - an edge.
Your query is working fine for me.
In my case I have the rid as #11:0 for professor, #12:0 for course and #13:0 for teaches
Just rerun your query once again or try the below :
traverse both('teaches') from #12:0
I am struggling, maybe the simplest problem ever. My SQL knowledge pretty much limits me from achieving this. I am trying to build an sql query that should show JobTitle, Note and NoteType. Here is the thing, First job doesn't have any note but we should see it in the results. System notes never and ever should be displayed. An expected result should look like this
Result:
--------------------------------------------
|ID |Title |Note |NoteType |
--------------------------------------------
|1 |FirstJob |NULL |NULL |
|2 |SecondJob |CustomNot1|1 |
|2 |SecondJob |CustomNot2|1 |
|3 |ThirdJob |NULL |NULL |
--------------------------------------------
.
My query (doesn't work, doesn't display third job)
SELECT J.ID, J.Title, N.Note, N.NoteType
FROM JOB J
LEFT OUTER JOIN NOTE N ON N.JobId = J.ID
WHERE N.NoteType IS NULL OR N.NoteType = 1
My Tables:
My JOB Table
----------------------
|ID |Title |
----------------------
|1 |FirstJob |
|2 |SecondJob |
|3 |ThirdJob |
----------------------
My NOTE Table
--------------------------------------------
|ID |JobId |Note |NoteType |
--------------------------------------------
|1 |2 |CustomNot1|1 |
|2 |2 |CustomNot2|1 |
|3 |2 |SystemNot1|2 |
|4 |2 |SystemNot3|2 |
|5 |3 |SystemNot1|2 |
--------------------------------------------
This can't be true together (NoteType can't be NULL as well as 1 at the same time):
WHERE N.NoteType IS NULL AND N.NoteType = 1
You may want to use OR instead to check if NoteType is either NULL or 1.
WHERE N.NoteType IS NULL OR N.NoteType = 1
EDIT: With corrected query, your third job will not be retrieved as JOB_ID is matching but its the row getting filtered out because of the where condition.
Try below as work around to get the third job with null values.
SELECT J.ID, J.Title, N.Note, N.NoteType
FROM JOB J
LEFT OUTER JOIN
( SELECT JOBID NOTE, NOTETYPE FROM NOTE
WHERE N.NoteType IS NULL OR N.NoteType = 1) N
ON N.JobId = J.ID
just exclude the systemNotes and use a sub-select:
select * from job j
left outer join (
select * from note where notetype!=2
) n
on j.id=n.jobid;
if you include the joined table into where then left outer join might work as an inner join.