how can i get age from date of birth in neo4j - date

I´m starting with neo4j and would like to know how to get the age in years.
I have the node below
(p1:Person{id:1,birthdate:"1989-10-03",name:"Person1"})
tried something like this
with p.birthdate as bd, date() as d return d - bd

You can use date and duration types, for instance like this:
MATCH (p:Person {name: "Person1"})
WITH duration.between(date(p.birthdate), date()) as d
RETURN d, d.years, d.months, d.days

If you like APOC functions (Awesome Procedures on Cypher) then below script will work:
MATCH (p:Person {name: "Person1"})
RETURN ( apoc.date.convert(timestamp(), 'ms', 'd') -
apoc.date.parse(p.birthdate, 'd', 'YYY-MM-DD')) / 365 as yearsAlive
Result:
╒════════════╕
│"yearsAlive"│
╞════════════╡
│33 │
└────────────┘
Ref:
1.https://neo4j.com/labs/apoc/#:~:text=APOC%20is%20an%20add%2Don,all%20APOC%20functions%20and%20procedures
2.https://neo4j.com/labs/apoc/4.0/overview/apoc.date/

Related

Writing a query in SQLAlchemy to count occurrences and store IDs

I'm working with a postgres db using SQLAlchemy.
I have a table like this
class Author(Base):
__tablename__ = "Author"
id = Column(BIGINT, primary_key=True)
name = Column(Unicode)
and I want to identify all homonymous authors and save their id in a list.
For example if in the database there are 2 authors named "John" and 3 named "Jack", with ID respectively 11, 22, 33, 44 a 55, I want my query to return
[("John", [11,22]), ("Jack", [33,44,55])]
For now I've been able to write
[x for x in db_session.query(
func.count(Author.name),
Author.name
).group_by(Author.name) if x[0]>1]
but this just gives me back occurrences
[(2,"John"),(3,"Jack")]
Thank you very much for the help!
The way to do this in SQL would be to use PostgreSQL's array_agg function to group the ids into an array:
SELECT
name,
array_agg(id) AS ids
FROM
my_table
GROUP BY
name
HAVING
count(name) > 1;
The array_agg function collects the ids for each name, and the HAVING clause excludes those with only a single row. The output of the query would look like this:
name │ ids
═══════╪════════════════════
Alice │ {2,4,9,10,16}
Bob │ {1,6,11,12,13}
Carol │ {3,5,7,8,14,15,17}
Translated into SQLAlchemy, the query would look like this:
import sqlalchemy as sa
...
q = (
db_session.query(Author.name, sa.func.array_agg(Author.id).label('ids'))
.group_by(Author.name)
.having(sa.func.count(Author.name) > 1)
)
Calling q.all() will return a list of (name, [ids]) tuples like this:
[
('Alice', [2, 4, 9, 10, 16]),
('Bob', [1, 6, 11, 12, 13]),
('Carol', [3, 5, 7, 8, 14, 15, 17]),
]
In SQLAlchemy 1.4/2.0-style syntax equivalent would be:
with Session() as s:
q = (
sa.select(Author.name, sa.func.array_agg(Author.id).label('ids'))
.group_by(Author.name)
.having(sa.func.count(Author.name) > 1)
)
res = s.execute(q)

How to convert a time from text to time format in postgresQL?

I have done this query in PostgreSQL:
select b.movement_category,
round(count(*)*100/case when count(*) = 0 then 1 else sum(count(*)) over () end::numeric,2) cnt_pct
from (
select distinct a.imei_number, a.movement_category
from dataview a
where a.data_capture_time between '2018-07-28' and '2018-07-28'
and a.movement_category <> ''
and fn_distance_km(23.728264,90.411367,cast(a.latitude as double precision),cast(a.longitude as double precision))<=20
) b
group by b.movement_category
Take a look at the documentation for formatting functions for converting various data types.
One example for your case could be:
SELECT to_timestamp('05 Dec 2000 15:15:20', 'DD Mon YYYY HH24:MI:SS')::TIME
which will return 15:15:20

getting formatted column value in postgres

I have a column in my table having values of format:
COURSE_214/MODULE_5825/SUBMODULE_123/..../GOAL_124/ACTIVITY_125.
I need value for goal i.e 124 from goal_124. I am planning to use 'regexp_split_to_array' but don't know how to use elements from array.
I am using postgres 9.2.
You can use split_part like so:
select split_part(split_part('COURSE_214/MODULE_5825/SUBMODULE_123/..../GOAL_124/ACTIVITY_125', '/GOAL_', 2), '/', 1)
i.e.
select split_part(split_part(fieldname, '/GOAL_', 2), '/', 1)
Result:
124
Using json_object():
select json_object(string_to_array(translate(params, '_', '/'), '/'))
from test
json_object
------------------------------------------------------------------------------------------------
{"COURSE" : "214", "MODULE" : "5825", "SUBMODULE" : "123", "GOAL" : "124", "ACTIVITY" : "125"}
(1 row)
select json_object(string_to_array(translate(params, '_', '/'), '/'))->>'GOAL' as goal
from test
goal
------
124
(1 row)
The column has a format suitable for json. I would suggest to change the type of the column to jsonb. The first query may be used as a converter.
After the conversion you would access the parameters in an easy way, e.g.:
select *
from test
where params->>'COURSE' = '214'
and (params->>'GOAL')::int > 120;
Simple select of all GOAL_ parameters (if there are more than one)
select ltrim(elem, 'GOAL_')
from (
select unnest(string_to_array(params, '/')) elem
from test
) sub
where elem like 'GOAL_%'
You may try using regular expressions, getting the string between slashes
select substring(your_column from '^.*/(.*)/.*$') from your_table
If you expect to find in that part the GOAL value, use
select substring(your_column from '/GOAL_(.*)/') from your_table

Coldfusion return query based on calculated age

I've got one site in ColdFusion where the client now wants to get a list of certain users who are over a particular age. Here's my code so far:
<cfset minRefAge = 21 >
<cfquery name="rsReferees" datasource="nbsa">
SELECT ID, userFirstName + ' ' + userLastName AS refName, userTown, userDOB, userAccess
FROM UsersSSO
WHERE (dateDiff("yyyy", userDOB, now() ) => #minRefAge#) AND userAccess = 4
</cfquery>
userDOB is my date of birth field. When I run it, I get the following error:
The SELECT statement includes a reserved word or an argument name that is misspelled or missing, or the punctuation is incorrect.
I can't spot the error. Could someone help?
Looks like your greater than or equal to sign is backwards. Other than that, your query looks fine to me.
SELECT ID, userFirstName + ' ' + userLastName AS refName, userTown, userDOB, userAccess
FROM UsersSSO
WHERE (dateDiff("yyyy", userDOB, now() ) >= #minRefAge#)
AND userAccess = 4
You may also need to put the ref age in quotes: '#minRefAge#'

Extracting values from non-standard markup strings in PostgreSQL

Unfortunately, I have a table like the following:
DROP TABLE IF EXISTS my_list;
CREATE TABLE my_list (index int PRIMARY KEY, mystring text, status text);
INSERT INTO my_list
(index, mystring, status) VALUES
(12, '', 'D'),
(14, '[id] 5', 'A'),
(15, '[id] 12[num] 03952145815', 'C'),
(16, '[id] 314[num] 03952145815[name] Sweet', 'E'),
(19, '[id] 01211[num] 03952145815[name] Home[oth] Alabama', 'B');
Is there any trick to get out number of [id] as integer from the mystring text shown above? As though I ran the following query:
SELECT index, extract_id_function(mystring), status FROM my_list;
and got results like:
12 0 D
14 5 A
15 12 C
16 314 E
19 1211 B
Preferably with only simple string functions and if not regular expression will be fine.
If I understand correctly, you have a rather unconventional markup format where [id] is followed by a space, then a series of digits that represents a numeric identifier. There is no closing tag, the next non-numeric field ends the ID.
If so, you're going to be able to do this with non-regexp string ops, but only quite badly. What you'd really need is the SQL equivalent of strtol, which consumes input up to the first non-digit and just returns that. A cast to integer will not do that, it'll report an error if it sees non-numeric garbage after the number. (As it happens I just wrote a C extension that exposes strtol for decoding hex values, but I'm guessing you don't want to use C extensions if you don't even want regex...)
It can be done with string ops if you make the simplifying assumption that an [id] nnnn tag always ends with either end of string or another tag, so it's always [ at the end of the number. We also assume that you're only interested in the first [id] if multiple appear in a string. That way you can write something like the following horrible monstrosity:
select
"index",
case
when next_tag_idx > 0 then substring(cut_id from 0 for next_tag_idx)
else cut_id
end AS "my_id",
"status"
from (
select
position('[' in cut_id) AS next_tag_idx,
*
from (
select
case
when id_offset = 0 then null
else substring(mystring from id_offset + 4)
end AS cut_id,
*
from (
select
position('[id] ' in mystring) AS id_offset,
*
from my_list
) x
) y
) z;
(If anybody ever actually uses that query for anything, kittens will fall from the sky and splat upon the pavement, wailing in horror all the way down).
Or you can be sensible and just use a regular expression for this kind of string processing, in which case your query (assuming you only want the first [id]) is:
regress=> SELECT
"index",
coalesce((SELECT (regexp_matches(mystring, '\[id\]\s?(\d+)'))[1])::integer, 0) AS my_id,
status
FROM my_list;
index | my_id | status
-------+----------------+--------
12 | 0 | D
14 | 5 | A
15 | 12 | C
16 | 314 | E
19 | 01211 | B
(5 rows)
Update: If you're having issues with unicode handling in regex, upgrade to Pg 9.2. See https://stackoverflow.com/a/14293924/398670