I am running a SQL query where I am trying to get both the DOB and Age field as blank (' ') as opposed to NULL.
I have managed to use the ISNULL function to change the DOB from 1900-01-01 to ' '. Originally my DOB was
SELECT isnull(DOB,'') DOB
which was bring back 1900-01-01 instead of NULL
With the code below the Age field is appearing as '0' rather then ' '. I'm not sure how to use the ISNULL function, as the Age field does not exist in the db table.
SELECT ISNULL(CASE WHEN CONVERT(DATE, DOB) = '1900-01-01' THEN ''
ELSE CONVERT(CHAR(10), DOB, 103) END, '') AS DOB,
ISNULL (DATEDIFF(hour,dob,GETDATE())/8766,'')Age,
Any help will be much appreciated, thanks :)
Some dummy data of the table:
ID | Name |Address |DOB | Gender | Email |
---------------------------------------------------------
01 | Max |Abc Road| 2000-12-19 | Male |Max#mail.net |
02 | Sam |TBH Road| null | Male |Sam#mail.net |
This is what im getting with my query
ID | Name |Address |DOB | Age | Email |
---------------------------------------------------------
01 | Max |Abc Road|2000-12-19 | 15 |Max#Gmail.net |
02 | Sam |TBH Road| | 0 |Sam#Gmail.net |
What I want to get however is:
ID | Name |Address |DOB | Age | Email |
---------------------------------------------------------
01 | Max |Abc Road|2000-12-19 | 15 |Max#Gmail.net |
02 | Sam |TBH Road| | |Sam#Gmail.net |
This is your age:
DATEDIFF(hour,dob,GETDATE())/8766
It is a number. To make it a string, do this:
cast(DATEDIFF(hour,dob,GETDATE())/8766 as varchar (15))
Then you can use isnull because your datatypes are the same
isnull(cast(DATEDIFF(hour,dob,GETDATE())/8766 as varchar (15)), '')
You could use a simple CASE statement.
case
when dob = ''
then ''
else datediff(hour, dob, getdate())/8766
end as [Age]
There's probably a more elegant way to do it though.
You need to convert the other to varchar because it is coming as int then all other cases for that column will come as int if u have'nt mention anything it will default takes 0
so need to change the all output to varchar()
SELECT ISNULL(CASE WHEN CONVERT(DATE, DOB) = '1900-01-01' THEN ''
ELSE CONVERT(CHAR(10), DOB, 103) END, '') AS DOB,
IIf((DATEDIFF(hour,DOB,GETDATE())/8766) is null,'',
cast((DATEDIFF(hour,DOB,GETDATE())/8766) as nvarchar(3))) Age
You can use nullif and cast for this
select ISNULL(CONVERT(CHAR(10), nullif(DOB,'1900-01-01'), 103),'') as DOB,
isnull(cast(DATEDIFF(hour,nullif(DOB,'1900-01-01'),GETDATE())/8766 as varchar),'') Age
Related
I have a field in a PostgreSQL table, name, with this format:
JOHN^DOE
BILLY^SMITH
FIRL^GREGOIRE
NOEL^JOHN
and so on. The format is LASTNAME^FIRSTNAME. The table has ID, name, birthdate and sex fields.
How can I do a SQL statement with GROUP BY FIRSTNAME only ? I have tried several things, and I guess regexp_match could be the way, but I don't know how to write a correct regular expression for this task. Can you help me ?
I would recommend split_part():
group by split_part(mycol, '^', 1)
Demo on DB Fiddle:
mycol | split_part
:------------ | :---------
JOHN^DOE | JOHN
BILLY^SMITH | BILLY
FIRL^GREGOIRE | FIRL
NOEL^JOHN | NOEL
Use regexp_replace. Note that '^' needs to be escaped, since in many regexp dialects it means the beginning of the line or or the string. Extending your example with one more name, and using group by on the first field:
select
count(*)
, regexp_replace(tmp_col, '\^.*', '')
from
(values
('JOHN^DOE')
, ('BILLY^SMITH')
, ('FIRL^GREGOIRE')
, ('NOEL^JOHN')
, ('JOHN^SMITH')
)
as tmp_table(tmp_col)
group by regexp_replace(tmp_col, '\^.*', '')
;
Prints:
count | regexp_replace
-------+----------------
1 | BILLY
2 | JOHN
1 | NOEL
1 | FIRL
(4 rows)
To group by on the second field, use a similar regex:
select
count(*)
, regexp_replace(tmp_col, '.*\^', '')
from
(values
('JOHN^DOE')
, ('BILLY^SMITH')
, ('FIRL^GREGOIRE')
, ('NOEL^JOHN')
, ('JOHN^SMITH')
)
as tmp_table(tmp_col)
group by regexp_replace(tmp_col, '.*\^', '')
;
Prints:
count | regexp_replace
-------+----------------
1 | JOHN
1 | GREGOIRE
1 | DOE
2 | SMITH
(4 rows)
I want to know how my sql like this my problem is every i remove my where clause in my code there have a error (Conversion failed when converting date and/or time from character string.) i remove may where clause because i want to see my all data, the figure below is example only i have so many data
This is the 1st table
| Entries | recordDate | Empid | Reference |
+-----------------------+-------------------------+--------+-----------+
| 0016930507201907:35I | 2019-05-07 00:00:00 000 | 001693 | 1693 |
| 0016930507201917:06O | 2019-05-07 00:00:00 000 | 001693 | 1693 |
| 0016930507201907:35I | 2019-05-08 00:00:00 000 | 001693 | 1693 |
| | 2019-05-08 00:00:00 000 | 001693 | 1693 |
2nd table
| LastName | FirstName | middleName | EmployeeNO |
+----------+-----------+------------+------------+
| Cruz | MA Kimberly | Castillo | 001693 |
this is i want to see
| Name | EmployeeNO | RecordDate | TimeIn | TimeOut |
+-------------------------+------------+-------------------------+--------+---------+
| CRUZ, MA KIMBERLY, CASTILLO | 001693 | 2019-05-07 00:00:00 000 | 07:35am | 05:06pm |
| CRUZ, MA KIMBERLY,CASTILLO | 001693 | 2019-05-08 00:00:00 000 | 07:35am |
this is my code please help me thank you advance for your helping
Select
B.LastName + ',' + B.FirstName + ',' + B.MiddleName[Name] ,
A.[RecordDate],
B.[EmployeeNO],
CONVERT(VARCHAR(08),MIN(IIF(ISNULL(CHARINDEX('I', A.[Entries], 0), 1) > 0, CAST( SUBSTRING(A.[Entries], LEN(A.[Entries]) - 5, 5) AS [TIME]), NULL)), 100) AS [TimeIn],
CONVERT(VARCHAR(08),MAX(IIF(ISNULL(CHARINDEX('O', A.[Entries], 0), 1) > 0,CAST(SUBSTRING(A.[Entries], LEN(A.[Entries]) - 5, 5) AS [TIME]), NULL)),100) AS [TimeOut]
FROM Employees [B]
INNER JOIN [DTR Upload] [A] ON B.EmployeeNo = A.EmpID
GROUP BY B.LastName, B.FirstName, B.MiddleName,B.[EmployeeNO], A.[recordDate]
ORDER BY A.[recordDate] asc, B.LastName +','+B.FirstName + ','+ B.MiddleName ASC
This works for the sample data you have provided. Note however, I assume that recordDate is a varchar, due to it not being a valid datetime value (if it were, 2019-05-07 00:00:00 000 would be 2019-05-07 00:00:00.000; note the . instead of the ). If recordDate isn't a varchar then you won't need need to include the STUFF and CONVERT expressions to "fix" the value in the VALUES operator. Really, however, you should not be storing date(time) data as a varchar; use the appropriate data type for your data (as these values have no time portion other than midnight, date would seem best).
I also return the TimeIn and TimeOut columns as the datatype time. Date and Time datatypes, in SQL Server, don't have a format they are binary values. If you want to display it in a 12 hour format then you need to configure that in your presentation layer, not your SQL:
--Table1 Sample Data
WITH Table1 AS(
SELECT V.Entries,
V.recordDate,
V.Empid,
V.Reference
FROM (VALUES('0016930507201907:35I','2019-05-07 00:00:00 000','001693',1693),
('0016930507201917:06O','2019-05-07 00:00:00 000','001693',1693),
('0016930507201907:35I','2019-05-08 00:00:00 000','001693',1693),
(NULL,'2019-05-08 00:00:00 000','001693',1693)) V(Entries,recordDate,Empid,Reference)),
--Table2 Sample Data
Table2 AS (
SELECT 'Cruz' AS LastName,
'MA Kimberly' AS FirstName,
'Castillo' AS middleName,
'001693' AS EmployeeNO)
--Solution
SELECT STUFF(CONCAT(', ' + T2.LastName, ', ' + T2.FirstName, ', ' + T2.middleName),1,2,'') AS [Name],
T2.EmployeeNO,
T1.recordDate,
MAX(CONVERT(time(0),CASE S.InOut WHEN 'I' THEN SUBSTRING(T1.Entries,15,5) END)) AS TimeIn,
MAX(CONVERT(time(0),CASE S.InOut WHEN 'O' THEN SUBSTRING(T1.Entries,15,5) END)) AS TimeOut
FROM Table1 T1
JOIN Table2 T2 ON T1.Empid = T2.EmployeeNO --These should really have the same name
CROSS APPLY(VALUES(CONVERT(datetime,STUFF(STUFF(T1.recordDate,11,1, 'T'),20,1,'.')),RIGHT(T1.Entries,1))) S(recordDate, InOut)
GROUP BY T2.EmployeeNO,
T1.recordDate,
T2.LastName,
T2.FirstName,
T2.middleName;
Is that what you are after?
;WITH CTE AS
(
SELECT EmployeeNO,
CONCAT(LastName, ',', FirstName, ',', MiddleName) Name,
RecordDate,
CASE WHEN RIGHT(Entries, 1) = 'I'
THEN CAST(REPLACE(RIGHT(Entries, 6), 'I', '') AS TIME)
END TimeIn,
CASE WHEN RIGHT(Entries, 1) = 'O'
THEN CAST(REPLACE(RIGHT(Entries, 6), 'O', '') AS TIME)
END TimeOut
FROM T1 INNER JOIN T2
ON T1.EmpId = T2.EmployeeNO
)
SELECT EmployeeNO,
Name,
RecordDate,
MIN(TimeIn) TimeIn,
MAX(TimeOut) TimeOut
FROM CTE
GROUP BY EmployeeNO,
Name,
RecordDate;
Returns:
+------------+------------------------+-------------------------+----------+----------+
| EmployeeNO | Name | RecordDate | TimeIn | TimeOut |
+------------+------------------------+-------------------------+----------+----------+
| 1693 | Cruz,Kimberly,Castillo | 2019-05-07 00:00:00 000 | 07:35:00 | 17:06:00 |
| 1693 | Cruz,Kimberly,Castillo | 2019-05-08 00:00:00 000 | 07:35:00 | |
+------------+------------------------+-------------------------+----------+----------+
Live Demo
Now, let's talk a bit about the real problems you have.
You are storing dates as string which is bad, always pick the right data type for your data, so you need to store dates as DATE. Also for the Entries has 3 info there, that means a lack of normalization, because it should be 3 column instead.
For example
+----------------+------+---------------------+
| Entries | Kind | EntriesDate |
+----------------+------+---------------------+
| 00169305072019 | 1 | 2019-05-07 07:35:00 |
| 00169305072019 | 0 | 2019-05-07 16:30:00 |
+----------------+------+---------------------+
This way, you won't fall in those issues and things becomes easy.
For the concatenation of the names, if you always needs to get a full name, I suggest that you use a computed column for that, then you don't need to concatenate the names every time
ALTER TABLE <Your Table Name Here>
ADD [FullName] AS CONCAT(LastName, ',', FirstName, ',', MiddleName);
Let's say I have a table with two numeric columns: NUM and DEN.
I need to extract the ratio NUM/DEN only if DEN isn't 0: otherwise the ratio should be 0.
Something like this:
select ID, [...] AS RATIO
from Table
where [...] is some kind of equivalent of the excel formula IF(DEN=0;0;NUM/DEN).
Is there a way to perform this kind of query?
Many thanks!
This should work:
case
when DEN = 0 then 0
else NUM/DEN
end
Yes, what you are looking for is case. It has two versions:
case [variable]
when [value1] then [output1]
when [value2] then [output2]
when [value3] then [output3]
...
else [outputdefault] end
and
case when [Boolean(True/false) expression 1] then [output1]
when [Boolean(True/false) expression 2] then [output2]
when [Boolean(True/false) expression 3] then [output3]
...
else [outputdefault] end
If SQL Server 2012 you can use : IIF
IIF ( boolean_expression, true_value, false_value )
If you are using SQL Server you could use case statement like w0lf mentioned or you could use iif statement like so:
select iif(age > 21, 'Allowed', 'Not Allowed') as status
from test;
Example:
create table test (
fullname varchar (20),
age int
);
insert into test values
('John', 10),
('Matt', 90),
('Jane', 25),
('Ruby', 80),
('Randy', null);
Result
| fullname | status |
|----------|-------------|
| John | Not Allowed |
| Matt | Allowed |
| Jane | Allowed |
| Ruby | Allowed |
| Randy | Not Allowed |
The same thing can be written as
select case when age > 21 then 'Allowed' else 'Not Allowed' end as status
from test;
case statement is used by many database engines.
If you are dealing with null and not null values, you could also use coalesce like so:
select fullname, coalesce(age, 999) as status
from test;
The result will be:
| fullname | status |
|----------|--------|
| John | 10 |
| Matt | 90 |
| Jane | 25 |
| Ruby | 80 |
| Randy | 999 |
At first you may think that coalesce does if age is null then 999 else age. It does that, sort-of, but in particular coalesce outputs the first non-null value in a list. So, coalesce(null, null, 45) will result in 45. coalesce(null, 33, 45) will result in 33.
Feel free to play around with SQL Fiddle: http://sqlfiddle.com/#!6/a41a7/6
I am processing a large list of church members in order to send them a letter. We want the letter to say "Dear John & Jane Smith". We will use Word to do the mail merge from an Excel sheet. The important thing is the male name has to always come first.
Each individual has their own row in the table I am using. They have a unique ID as well as a family ID. I am using that family ID to put families together on the same row. Currently I have the male name and the female name separated using MAX(CASE WHEN) in order to specify what goes where. It looks something like this:
+-----------+------------+--------------------------+
| family id | male name | female name | last name |
+-----------+------------+--------------------------+
| 1234 | john | jane | doe |
| 1235 | bob | cindy | smith |
| 1236 | NULL | susan | jones |
| 1237 | jim | NULL | taylor |
+-----------+------------+--------------------------+
But I run into a problem when the family only has one member.
Here's a part of the query I have:
SELECT
fm.family_id AS 'Family ID',
MAX(CASE WHEN PB.gender like 'm' and FM.role_luid=29 THEN PB.nick_name END)
AS 'Male Name',
MAX(CASE WHEN PB.gender like 'f' and FM.role_luid=29 THEN PB.nick_name END)
AS 'Female Name',
PB.last_name AS 'Last Name',
FROM core_family F
I was thinking that I need to combine rows using STUFF or something like that, but I'd need some way of specifying which column comes first so that the male name always comes first. Essentially, as stated above, I need the letter to read "Dear John & Jane Smith" for families with two people and "Dear John Smith" for families with one person. So I am hoping my results might look like:
+-----------+--------------+-----------+
| family id | First name | last name |
+-----------+--------------+-----------+
| 1234 | john & jane | doe |
| 1235 | bob & cindy | smith |
| 1236 | susan | jones |
| 1237 | jim | taylor |
+-----------+--------------+-----------+
You can use your intermediate table (assuming you don't have 3 names for a family id).
From the table you indicated use:
select
id
, coalesce(male_name+' & '+female_name,male_name, female_name)
, last_name
from F;
Here is an example with your data
Basically if you concatenate using + in Sql Server you will get null. So if either male or female name is NULL, you get NULL. Coalesce will move on to the next value if it sees NULL. This way you either get a pair with '&' or a single name for each family.
I've created some test data. This technique works with the test data.
CREATE TABLE #Temp (FamID INT,
MaleName VARCHAR(20),
FemaleName VARCHAR(20),
LName VARCHAR(20))
INSERT #Temp
VALUES (1234, 'John' ,'Jane' , 'Doe' ),
(1235, 'Bob' , 'Cindy' , 'Smith'),
(1236 , NULL , 'Susan' , 'Jones'),
(1237 , 'Jim' , NULL , 'Taylor')
Here is your query.
SELECT FamID,
ISNULL(MaleName+' ','') +
CASE WHEN MaleName IS NULL OR FemaleName IS NULL THEN '' ELSE 'and ' END+
ISNULL(FemaleName,'') AS FirstName,
LName
FROM #Temp
You can use like this
SELECT
fm.family_id AS 'Family ID',
MAX(CASE WHEN PB.gender like 'm' and FM.role_luid=29 THEN PB.nick_name END)
+ '&'+
MAX(CASE WHEN PB.gender like 'f' and FM.role_luid=29 THEN PB.nick_name END)
AS 'First Name',
PB.last_name AS 'Last Name',
FROM core_family F
Running a query to send email subscribers a +X day email. FIRST_PROMO_SUBSCRIBE_DATE is coming from Oracle which they say is not a compatible format from Salesforce SQL so I have;
select * from PROMO_SUBSCRIBERS
where
(ORDER_ENGAGEMENT_LAST_DT > dateadd(day,-335,CAST(FLOOR(CAST(GETDATE() AS FLOAT)) AS DATETIME))
or ORDER_ENGAGEMENT_LAST_DT is null)
and
(ORDER_LAST_DT > dateadd(day,-1,CAST(FLOOR(CAST(GETDATE() AS FLOAT)) AS DATETIME))
or order_last_dt is null)
Are the parentheses correct?
You should just be able to cast the Oracle dates to date. Casting to date will also strip the time portion off of the datetime fields in T-SQL.
SQL Fiddle
MS SQL Server 2008 Schema Setup:
CREATE TABLE promo_subscribers
(
emailaddress varchar(255)
, ORDER_ENGAGEMENT_LAST_DT varchar(15)
, ORDER_LAST_DT varchar(15)
);
INSERT INTO promo_subscribers
(emailaddress, ORDER_ENGAGEMENT_LAST_DT, ORDER_LAST_DT)
VALUES
('test#example.com', '01-APR-98', '01-APR-16'),
('test#example.com', '01-MAY-98', '06-APR-16')
Query 1:
select
emailaddress
, order_engagement_last_dt
, cast(order_engagement_last_dt as date) datecast1
, order_last_dt
, cast(order_last_dt as date) datecast2
, dateadd(day,-335, cast(getDate() as date)) datecast3
, dateadd(day,-1, cast(getDate() as date)) datecast4
from PROMO_SUBSCRIBERS
Results:
| emailaddress | order_engagement_last_dt | datecast1 | order_last_dt | datecast2 | datecast3 | datecast4 |
|------------------|--------------------------|------------|---------------|------------|------------|------------|
| test#example.com | 01-APR-98 | 1998-04-01 | 01-APR-16 | 2016-04-01 | 2015-05-08 | 2016-04-06 |
| test#example.com | 01-MAY-98 | 1998-05-01 | 06-APR-16 | 2016-04-06 | 2015-05-08 | 2016-04-06 |