SQL Find Age using DateDiff - sql

Fields || Data
ID || V465
DOB || 1946-09-05
DATE_OF_DEATH || 1974-05-11
I am using this SQL but I am getting an error.
select DATEDIFF("YYYY",'DOB','DATE_OF_DEATH') where ID= 'V465'
Its SQL SERVER Management Studio R2 and
Error: Msg 207, Level 16, State 1, Line 2
Invalid column name 'ID'

You forgot the FROM (and surrounded your column names with single quotes which treats them as string literals):
select DATEDIFF("YYYY",DOB,DATE_OF_DEATH)
FROM {tablename}
where ID= 'V465'
And DATEDIFF alone is not the right way to determine "age" since
DATEDIFF("yyyy",'2001-12-01','2003-01-31')
will give you 2 instead of 1.
See one method here and another here

that error most likely comes from not including a table in your select statement
select DATEDIFF(YY,DOB,DATE_OF_DEATH) AS AGE
FROM TABLE_NAME
where ID= 'V465'

SELECT DATEDIFF(YY,'01-01-2001','12-31-2002')
Returns 1 on MSSQL

Test Data
DECLARE #TABLE TABLE(ID VARCHAR(20),DOB DATE, DATE_OF_DEATH DATE)
INSERT INTO #TABLE VALUES
('V465', '1946-09-05', '1974-05-11'),('V466', '1945-09-05', '2000-11-11'),
('V467', '1982-09-05', NULL),('V468', '1946-09-05', NULL)
Query
SELECT DATEDIFF(YEAR,DOB, COALESCE(DATE_OF_DEATH, GETDATE())) AS AGE
FROM #TABLE
Using COALESCE function if someone hasnt died yet you can calculate their age too. COALESCE function will take difference from date of death and if the column is null it will take difference from today's date. and will give you the following result.
Result
╔═════╗
║ AGE ║
╠═════╣
║ 28 ║
║ 55 ║
║ 32 ║
║ 68 ║
╚═════╝

Related

Cleaning data by adding/removing characters to a string when it meets certain conditions T-SQL

I'm looking for help with cleaning a column in my data set so that I can join to another table.
The first data set is my complete data and includes what we call "reference_numbers" which relate to a specific case. Here is a dummy sample:
reference_number
case_opened
case_closed
01353568-00000001
11/01/2021
03/02/2022
09736473-00000009
21/04/2005
19/07/2021
05839576-00000012
13/09/2014
19/12/2017
09364857-00000006
13/09/2014
19/12/2017
As you can see, the "reference_number" is 8 digits then hyphen (-) and then another 8 digits. This is how a reference number should look.
My second data set is full of the same "reference_numbers". However, there is inconsistencies in the character length as they are often written differently by individuals:
reference_number
Case_workers
1353568-00000001
5
09736473-9
10
5839576-12
7
09364857-000000006
4
The first reference_number in the second data set is missing the
first "0"
The second reference_number in the second data set is missing seven "0" after the hyphen
The third reference_number in the second data set is missing both the first "0" and six "0" after the hyphen
The fourth reference_number in the second data set has too many digits after the hyphen (there is supposed to be seven 0's)
I want to be able to join the first data set onto the second data set using the reference_number. However, I need to clean them first. Is this possible and is there any efficient way of doing this?
Thanks
If the rules are so specific, you could try to use a combination of STRING_SPLIT and STRING_AGG:
SELECT
t.reference_number,
STRING_AGG(RIGHT('00000000'+s.value,8),'-') new_reference_number
FROM dbo.SecondTable t
CROSS APPLY STRING_SPLIT(t.reference_number,'-') s
GROUP BY t.reference_number
;
Using the sample data you posted, the results are:
╔════════════════════╦══════════════════════╗
║ reference_number ║ new_reference_number ║
╠════════════════════╬══════════════════════╣
║ 09364857-000000006 ║ 09364857-00000006 ║
║ 09736473-9 ║ 09736473-00000009 ║
║ 1353568-00000001 ║ 01353568-00000001 ║
║ 5839576-12 ║ 05839576-00000012 ║
╚════════════════════╩══════════════════════╝
select reference_number,
CONCAT(left(reference_number, charindex('-', reference_number) - 1),'-',RIGHT(CONCAT('000000000',right(reference_number, len(reference_number) - charindex('-', reference_number))),9)) as NewReferenceNumber
from YourSecondTableName
Reference_Number
New_Reference_Number
1353568-00000001
1353568-000000001
09736473-9
09736473-000000009
5839576-12
5839576-000000012
09364857-000000006
09364857-000000006

Multiple IN Conditions on a DELETE FROM query throwing a #245 Conversion Type Error

I have a table setup like the following:
Parameters
╔═══╦═════════╦════════╗
║ID ║ Name ║ Value ║
╠═══╬═════════╬════════╣
║ 7 ║ first ║ 0 ║
║ 7 ║ second ║ -1 ║
║ 7 ║ third ║ -1 ║
╚═══╩═════════╩════════╝
It contains more rows, but I only want to delete the ones listed above. I have made the following query below to perform this action, but when you add a 3rd value to the IN condition for name I get:
ErrorNumber 245 - "Conversion failed when converting the varchar value to data type int."
DELETE FROM Parameters
WHERE
ID = 7 AND
Name IN ('first', 'second', 'third') AND
Value IN (0, -1)
If I delete any of the 3 names making the IN condition 1 or 2 names it runs fine, but I need the third row to be deleted in the same query. What can I do to accomplish this?
Clearly, either id or value is a string. SQL Server has to decide what type to use. If a string is compared to a number, then a number is used. If another row has a bad number, then you get a type conversion error.
You should use the proper types for comparison. If I had to guess, it would be value:
DELETE FROM Parameters
WHERE
ID = 7 AND
Name IN ('first', 'second', 'third') AND
Value IN ('0', '-1');
You can put single quotes around numeric constants such as 7. I discourage it, because mis-using types is a bad coding habit.

How to UNPIVOT a table in SQL Server?

I'm trying to unpivot my data but getting some weird results. How can I accomplish this?
Below is my code and screenshot of the results. (SQL Fiddle)
select distinct recId, caseNumber, servtype, mins
from
(
select
recid
,caseNumber
,[preEnrollment_type]
,[preEnrollment_minutes]
,[screening_type]
,[screeningEnA_minutes]
,[ifsp_type]
,[ifsp_minutes]
from
CaseManagementProgressNote
where
[formComplete]=1
and [reviewed]<>1
and [dataentry]<>1
and [caseManagementEntry]=1
and [serviceCoordinator] <> 'webmaster#company.net'
and [contactDateTime] >= '1/1/2015'
and [childID] is not null
) as cp
unpivot
(
servType for servTypes in ([preEnrollment_type],[screening_type],[ifsp_type])
) as up1
unpivot
(
mins for minutess in ([preEnrollment_minutes],[screeningEnA_minutes],[ifsp_minutes])
) as up2
order by
recId
Top part is the strange unpivoted data and the bottom part is the actual table.
As you can see in the unpivoted data, the [column]_type repeats twice and has incorrect corresponding values.
I need
1439 964699 -NA- null
1439 964699 SC 45
1439 964699 TCM FF 20
Take also into account that I still have more columns to select.
This is the reference I was using mssqltips
SQL Fiddle of the example above.
You seem to have the impression that your two UNPIVOT operations are somehow linked. They're not, other than that the second UNPIVOT is performed on the result of the first.
If you look at the results of your first UNPIVOT:
select *
from
(
select
recid
,caseNumber
,[preEnrollment_type]
,[preEnrollment_minutes]
,[screening_type]
,[screeningEnA_minutes]
,[ifsp_type]
,[ifsp_minutes]
from
CaseManagementProgressNote
) as cp
unpivot
(
servType for servTypes in ([preEnrollment_type],[screening_type],[ifsp_type])
) as up1
You will see
╔═════════╦═════════════╦════════════════════════╦═══════════════════════╦═══════════════╦═══════════╦════════════════════╗
║ recid ║ caseNumber ║ preEnrollment_minutes ║ screeningEnA_minutes ║ ifsp_minutes ║ servType ║ servTypes ║
╠═════════╬═════════════╬════════════════════════╬═══════════════════════╬═══════════════╬═══════════╬════════════════════╣
║ 143039 ║ 964699 ║ (null) ║ 45 ║ 20 ║ -NA- ║ preEnrollment_type ║
║ 143039 ║ 964699 ║ (null) ║ 45 ║ 20 ║ SC ║ screening_type ║
║ 143039 ║ 964699 ║ (null) ║ 45 ║ 20 ║ TCM FF ║ ifsp_type ║
╚═════════╩═════════════╩════════════════════════╩═══════════════════════╩═══════════════╩═══════════╩════════════════════╝
It should be clear from this what the second UNPIVOT operation does, why it gives you the results it does: to get your desired result from this, you don't need to unpivot. UNPIVOT transforms columns to rows. That's not what you're looking for. You already have the rows you want. What you want is to put all three minutes columns together in one single column, depending on the servTypes. There are ways to do that, for instance by adding an expression to your SELECT list, like so:
CASE servType
WHEN 'preEnrollment_type' THEN preEnrollment_minutes
WHEN 'screening_type' THEN screeningEnA_minutes
WHEN 'ifsp_type' THEN isfp_minutes
END
Or use #ander2ed's approach and drop the UNPIVOT entirely, if you don't mind that it doesn't filter out the NULLs.
The article you link to covers this problem too:
The only complication here is matching the output phone to the corresponding phone type - for this we need to do some string interrogation to ensure that Phone1 matches to PhoneType1, Phone2 matches to PhoneType2, etc.
It solves it by doing the second UNPIVOT, and then filtering the results. You can make it work by linking servTypes and minutess. In your particular sample data, the first character of them is sufficient for identification, and is the same in the two columns, so you could add where left(servTypes, 1) = left(minutess, 1) to your query.
This seems pointlessly complicated to me, and I wouldn't recommend it, but it's the difference between the article and your query, it's the reason your query doesn't work when the article's does.
You can use Cross Apply in place of unpivot here. I find the syntax much easier to understand, and you will be able to retain null values. Try something like:
select recid, casenumber, servtype, mins
from CaseManagementProgressNote a
cross apply (VALUES (preEnrollment_type, preEnrollment_minutes),
(screening_type, screeningEna_Minutes),
(ifsp_type, ifsp_minutes)) unpvt (servtype, mins)

Squeryl update from select?

Given the following widgets table
╔════╦═════════╦═════╗
║ id ║ prev_id ║ foo ║
╠════╬═════════╬═════╣
║ 1 ║ ║ bar ║
║ 2 ║ 1 ║ ║
╚════╩═════════╩═════╝
And the following sql query
UPDATE widgets
SET
widgets.foo =
(
SELECT widgets.foo
FROM widgets
WHERE widgets.id = 1
)
WHERE
widgets.id = 2
How do I do the above update in squeryl?
I tried
update(widgets) (
w=>
where(w.id === 2)
set(w.foo := from(widgets)(prevW => where(prevW.id === 1) select foo))
)
But that gave me the following compile error:
error: No implicit view available from org.squeryl.Query[Option[String]] => org.squeryl.dsl.ast.TypedExpressionNode[Option[org.squeryl.PrimitiveTypeMode.StringType]].
It looks like Squeryl added support for sub queries with https://github.com/max-l/Squeryl/commit/e75ddecf4a0855771dd569b4c4df4e23fde2133e
However it needs an aggregate query that is guaranteed to return one result. This is done with the compute clause.
I came up with a workaround using compute(min(foo)).
So my solution ends up looking like
update(widgets) (
w=>
where(w.id === 2)
set(w.foo := from(widgets)(prevW => where(prevW.id === 1) compute(min(foo))))
)
Maybe there should be a single aggregate function that throws an exception if the query returns more than one result.
Related conversations:
https://groups.google.com/d/msg/squeryl/F9JZsPlsjVU/j1FsD7ZDJ08J
https://groups.google.com/d/msg/squeryl/6ZRMk4I9vZU/CGSiE8q3MpAJ

Comparing two tables for each column of each row and result as log variable

I need to compare two tables in each row. the tables are as follows:-
Table a:
ID First_Name Last_name Birthdate
1 Shradha Deshkmukh 1981-12-25 00:00:00
2 Shradha Verma 1981-05-11 00:00:00
3 Divya Dutta 1982-07-21 00:00:00
4 Matthew Palmer 1983-12-28 00:00:00
table d:-
id fn ln dob
1 Shradha Tiwari 1981-12-25 00:00:00
2 Divya Dutta 1983-07-21 00:00:00
3 Sulabh Manesar 1975-09-11 00:00:00
4 Matthew Palmer 1983-12-28 00:00:00
5 Samuel Maxwell 1984-05-22 00:00:00
Now my original table is having about 17 columns and this is just a simpler version of it. The tables 'A' and 'D' are generated by a query. Table 'A' will be populated and Table D will be like a temporary table that gets its values from the query, compares all the First Names of each table and if it encounters any change , it needs to update the log table By the first name and also mentions all the columns that are different.
For this I have created a temporary table, viz. '#TMP_COMPARE' which takes all the columns of table 'a'. and then compares those columns against that of table 'd' and it has the columns PLN, PDOB, Pmatch which have values 0 by default and are set to one in case all columns match for that row(Pmatch=1), Last name matches (PLN=1), Dob matches (Pdob=1).
Once this '#TMP_COMPARE' compares the two tables I will then update the log table with the columns that dont match for a first name.
USE Testing
GO
IF OBJECT_ID('TEMPDB..#TMP_COMPARE') is not null
BEGIN
DROP TABLE #TMP_COMPARE
END
CREATE TABLE #TMP_COMPARE(
FN varchar(20),
LN varchar(20),
dob smalldatetime,
PLN int default 0,
Pdob int default 0,
Pmatch int default 0)
BEGIN
INSERT INTO #TMP_COMPARE
SELECT a.fn, a.ln, a.dob,
case when a.ln = d.Last_name AND a.dob = d.Birthdate
THEN 1
END AS #TMP_COMPARE.PMATCH,
CASE WHEN a.dob <> d.Birthdate
THEN 0
WHEN a.dob = d.Birthdate then 1
END AS #TMP_COMPARE.Pdob,
CASE WHEN a.ln <> d.Last_name
THEN 0
WHEN a.ln = d.Last_name
then 1
END AS #TMP_COMPARE.PLN
FROM dbo.a2 as a
JoIN d ON a.fn = d.First_Name
END
SELECT * FROM #TMP_COMPARE
Error I am getting is :-
Msg 102, Level 15, State 1, Line 24
Incorrect syntax near '.'
What is wrong in my query, and should I do this any other way please advice.
Now this is something very basic that is wrong in my query but I am a newbie and any help is very much appreciated.
Thanks in advance,
DCS
#log is a single scalar variable value and can only hold a single value at a given time. So you are unable to reference previous values of that variable, just what is currently there.
That means it's only going to display the last value (match) for every record in your select statement.
You may want to move the select inside the loop and change it to an insert into a logging table of some sort. That way you can just select * from loggingtable after the loop is over to retrieve all the data.
There is likely a way better way to handle this also, but I wanted to give a quick response (no time to refactor right now).
You can use a two character data field to store a result.
Position 1 = LN match state
Position 2 = Birthdate match state
11 = LN Match True ; Birthday Match True
10 = LN Match True ; Birthday Match False
01 = LN Match False; Birthday Match True
00 = LN Match False; Birthday Match True