I should find gender of employees from their (SSN).and theory is , if the last number of SSN is even (0,2,4,6,8) gender is woman or/else if the last number of SSN is odd (1,3,5,7,9) gender is man.
SSN of employees look like this in my DataBase ,for ex : 1111112020 or 22222231 - and column name is XX and datatype is nvarchar(30).
The sql i wrote look like this to find out gender of employees and when i executed query i get NULL. Can someone please point me in the right direction. Thanks.
DECLARE #Mand char(5) = '1,3,5,9,7'
DECLARE #Woman char(5) = '0,2,4,6,8'
DECLARE #Gender char (1)
SELECT (
CASE
WHEN right(rtrim(SSN),1) = #Mand THEN 'MAN'
WHEN right(rtrim(SSN),1) = #Woman THEN 'Woman'
ELSE NULL
END) as gender
FROM U
WHERE I = XXX
You cannot use strings and in that way. Just use the explicit list in the query:
SELECT (CASE WHEN right(rtrim(SSN), 1) IN ('1', '3', '5', '7', '9') THEN 'MALE'
WHEN right(rtrim(SSN), 1) IN ('2', '4', '6', '8', '0') THEN 'FEMALE'
END) as gender
FROM dbo.Users
WHERE CustomerId = 214;
Alternatively, you could use LIKE:
SELECT (CASE WHEN rtrim(SSN) LIKE '%[13579]' THEN 'MALE'
WHEN rtrim(SSN) LIKE '%[24680]' THEN 'FEMALE'
END) as gender
FROM dbo.Users
WHERE CustomerId = 214;
I should note that I am not aware that gender is assigned this way for US social security numbers.
Assuming that your SSNs are guaranteed valid (i.e. only contain digits), then the expression RIGHT(SSN,1)%2 (or RIGHT(RTRIM(SSN),1)%2 if there's extra space at the end) will return 0 for females and 1 for males. There's no need for complex string searching when things have been set up to make maths easy.
You can then optionally put that in a CASE if you want to, e.g.
CASE RIGHT(SSN,1)%2
WHEN 0 THEN 'Female'
ELSE 'Male'
END
DECLARE #ie nvarchar(30)
SET #ie = '1111112020'
SELECT (
CASE
WHEN right(rtrim(#ie),1) IN ('1','3','5','9','7') THEN 'MAN'
WHEN right(rtrim(#ie),1) IN ('0','2','4','6','8') THEN 'Woman'
END ) as gender
Related
I've tried writing my sql query to select multiple records on to one row but it isn't working the way I expected it to
Currently my table looks something like this
person id
fruit
1
apple
1
orange
1
banana
2
apple
2
orange
3
apple
I've tried using CASE and GROUP BY but it just gave extra records and didn't display the way I wanted it to and is displaying like this
SELECT DISTINCT
F.MEMBER
,F.GIVEN_NAMES
,F.SURNAME
--VALUES NEEDED
,CASE WHEN F.VALUE_NEEDED = 'Postal Address' THEN 'Yes' ELSE '' END POSTAL_ADDRESS
,CASE WHEN F.VALUE_NEEDED = 'Birthday' THEN 'Yes' ELSE '' END BIRTHDAY
,CASE WHEN F.VALUE_NEEDED = 'Email Address' THEN 'Yes' ELSE '' END EMAIL_ADDRESS
,CASE WHEN F.VALUE_NEEDED = 'First Name' THEN 'Yes' ELSE '' END FIRST_NAME
,CASE WHEN F.VALUE_NEEDED = 'Surname' THEN 'Yes' ELSE '' END SURNAME
,CASE WHEN F.VALUE_NEEDED = 'Title and Gender' THEN 'Yes' ELSE '' END 'TITLE|GENDER'
,CASE WHEN F.VALUE_NEEDED = 'Mobile' THEN 'Yes' ELSE '' END MOBILE
,CASE WHEN F.VALUE_NEEDED = 'Beneficiary' THEN 'Yes' ELSE '' END BENEFICIARY
FROM #FINAL F
GROUP BY F.MEMBER,F.GIVEN_NAMES
,F.SURNAME,VALUE_NEEDED
ORDER BY F.MEMBER
person id
apple
orange
banana
1
yes
1
yes
1
yes
How do I write the query so it looks more like this?
person id
apple
orange
banana
1
yes
yes
yes
2
yes
yes
3
yes
You are almost there, just needed to add the max and group by to aggregate it . This used to be a typical interview question back then.
Some thing like this if I understood correctly
with t as
(
select 1 as person_id, 'apple' fruit
union
select 1 ,'orange'
union
select 1 ,'banana'
union
select 2 ,'apple'
union
select 2 ,'orange'
union
select 3 ,'apple'
)
, b as
(
select
person_id,
case when fruit= 'apple' then 'yes' else null end 'apple',
case when fruit= 'orange' then 'yes' else null end 'orange',
case when fruit= 'banana' then 'yes' else null end 'banana'
from t
)
select
person_id,
max(apple) apple,
max(orange) orange,
max(banana) banana
from b
group by 1;
person_id
apple
orange
banana
1
yes
yes
yes
2
yes
yes
NULL
3
yes
NULL
NULL
You have tagged the tool that you are using (SQL Server Management Studio) which can be used with different DBMS. As Microsoft's SQL Server is the most typical used in this tool, I assume your are using that.
First let's look at your table. It seems a bit weird. It seems to be a kind of key-value table (aka EAV). Each row tells us for an attribute whether it is needed for a person. Now how to identify a person in the table? Is the column member a unique person ID? Probably not, because then, what would be given_names and surname be for in that table, that can change with every entry. Why would the same person with the ID 1234 be called John Smith when the value_needed is 'Birthday', but be called 'Anne Miller' when value_needed is 'Mobile'? That wouldn't make much sense. So maybe member is just a flag, whether a person is a member or not, and a person is uniquely identified by their given_names and surname. But then again, why would the same person John Smith be a member when value_needed is 'Birthday', but not a member when value_needed is 'Mobile'? So something is amiss here. It seems your table is not normalized. Better have one person table and one table for the attributes.
That being said, GROUP BY ___ means "I want one result row per ___". You group by the person and their value_needed. But you don't want one result row per person and value_needed. You want one resut row per person. Hence, group by person.
Then you SELECT DISTINCT .... This means you want to remove duplicate rows. But look at the rows you are selecting. There are no duplicates. If you use GROUP BY, you can be 99.99% sure you don't need DISTINCT. (There do exist rare situations where you voluntarily group by columns, don't select all of them and then apply DISTINCT, but these are so rare that you probably won't ever use them at all.)
Now to the task: You want to get from rows to columns. This is called pivot and can be achieved with the PIVOT keyword, but it is more common to use conditional aggregation. "Conditional aggregation" means that you aggregate your data (per person) and then apply a condition. In standard SQL:
SELECT MIN('YES') FILTER (WHERE f.value_needed = 'Postal Address')
You can use MIN or MAX here, and it is only required for syntax reasons (the FILTER clause must refer to some aggregation function.
In SQL Server there is no FILTER clause, so you use a CASE expression instead:
SELECT MIN(CASE WHEN f.value_needed = 'Postal Address' THEN 'YES' END)
If you want the empty string '' instead of NULL, apply COALESCE:
SELECT COALESCE(MIN(CASE WHEN f.value_needed = 'Postal Address' THEN 'YES' END), '')
Columns aliases containing special characters like | require quoting. But not single quotes, as these denote string literals. In standard SQL use double quotes, in SQL Server use brackets. But better, just avoid them alltogether, by avoiding special characters in names.
The complete query:
SELECT
person_id,
MIN(CASE WHEN value_needed = 'Postal Address' THEN 'yes' end) AS postal_address,
MIN(CASE WHEN value_needed = 'Birthday' THEN 'Yes' end) AS birthday,
MIN(CASE WHEN value_needed = 'Email' THEN 'Yes' END) AS email_address,
MIN(CASE WHEN value_needed = 'First Name' THEN 'Yes' END) AS first_name,
MIN(CASE WHEN value_needed = 'Surname' THEN 'Yes' END) AS surname,
MIN(CASE WHEN value_needed = 'Title and Gender' THEN 'Yes' END) AS title_gender,
MIN(CASE WHEN value_needed = 'Mobile' THEN 'Yes' END) AS mobile,
MIN(CASE WHEN value_needed = 'Beneficiary' THEN 'Yes' END) AS beneficiary
FROM #FINAL
GROUP BY person_id
ORDER BY person_id;
I have a question about how to accomplish something in SQL Server. Basically, I want to take a set of data comes from a certain time period, and remove any rows where a column value, in this case SerialNumber, has been entered in the previous 3 weeks and has a passing mark. I filter based on the current date to return any potentially relevant entries. Below is that data.
The issue is that the final entry in that above data has an entry date before the current date and in the previous 3 weeks time period, and it result has a pass of '1'. As such, I'd like to remove any entries for that SerialNumber value so it's not listed in today's results. The desired data is below.
Hopefully this makes sense to you guys. It's hard for me to describe. Current query Code is below, if needed. It doesn't make an attempt to implement the desired functionality as I'm not sure how to go about it.
Select * From
(SELECT A.SerialNumber
,[EndTime] as Date
,ROW_NUMBER() over (partition by A.SerialNumber order by EndTime desc) Entry
,[Pass]
,A.EntryTotal
,A.Passes
,CycleType
From
(
SELECT max([SerialNumber]) as SerialNumber
,Count(*) as EntryTotal
,sum(convert(int,TD.Pass)) as Passes
FROM [FlowDB2].[dbo].[TimeAnalyticsData] TD
where Pass is not null
group by SerialNumber
)
as A join [FlowDB2].[dbo].[TimeAnalyticsData] as TAD on A.SerialNumber = TAD.SerialNumber
inner join [FlowDB2].[dbo].[TimeAnalytics] as TA on TAD.DurationID = TA.DurationID
where
Pass is not null
and
(EndTime >= '2020-08-24 16:00:00' and EndTime < '2020-08-25 4:00:00')
) as B
A correlated subquery allows you to compare data to itself.
The following looks for the non-existence of rows with the same SerialNumber as the current row with pass=1 less than 21 days ago.
The final filter simply makes sure you're looking at a different date than the current one.
select *
from original_data od1
where not exists (select null
from original_data od2
where and od2.pass = 1
and od2.serialnumber = od1.serialnumber
and od2."Date" > DATEADD(day, -21, od1.date)
and od2."Date" <> od1."Date"
);
with your original data recreated as follows:
CREATE TABLE original_data (
"SerialNumber" BIGINT,
"Date" datetime,
"Entry" INTEGER,
"Pass" INTEGER,
"EntryTtl" INTEGER,
"Passes" INTEGER,
"CycleTy" VARCHAR(2)
);
INSERT INTO original_data
("SerialNumber", "Date", "Entry", "Pass", "EntryTtl", "Passes", "CycleTy")
VALUES
('6102046905', '2020-08-24 21:03:20.000', '1', '1', '2', '1', 'PA'),
('6102046905', '2020-08-24 19:47:23.000', '2', '0', '2', '1', 'PA'),
('6102046906', '2020-08-24 22:45:16.000', '1', '1', '2', '1', 'PA'),
('6102046906', '2020-08-24 19:47:23.000', '2', '0', '2', '1', 'PA'),
('6102047024', '2020-08-24 21:03:20.000', '1', '1', '2', '1', 'PA'),
('6102047024', '2020-08-24 19:47:23.000', '2', '0', '2', '1', 'PA'),
('6102047028', '2020-08-24 18:04:48.000', '1', '1', '2', '1', 'PA');
See how it works in this Fiddle.
I have a table that stores students exam results. In that table I have a nvarchar column REMARKS; if obtained marks are less then passing marks, the system adds Pass/Fail to Remarks in that particular column.
The problem is now I am showing whole result with total marks obtained and also display if a student has passed or failed, based on the a query like
If remarks = 'Fail'
and fail is more than one subject in that exam than display Fail else Pass. I searched and tried a lot but no luck. can anyone please tell me how to get it done?
Thanks!
UPDATE:
Tried so far:
SELECT
StudentName,
Year,
ExamType,
SUM(TotalMarks) AS TotalMarks,
SUM(ObtainedMarks) AS ObtMarks
FROM
[dbo].[Exam]
WHERE
ExamType = #Type AND Year = #Year
Looking for a query something like:
CASE WHEN [Remarks] = 'Fail' and having count > 1 THEN 'Fail' ELSE 'Pass' End as 'Status'
The following query returns 'fail' is there is more than one fail in the ExamType and year for a student
SELECT StudentName
,#Year
,#Type
,Sum(TotalMarks) as TotalMarks
,Sum(ObtainedMarks) as ObtMarks
,CASE WHEN Count(CASE WHEN [Remarks] = 'Fail' THEN 1 END) > 1 THEN 'Fail' ELSE 'Pass' End as 'Status'
FROM [dbo].[Exam]
Where ExamType = #Type And Year = #Year
Group by StudentName
I'm working a query that will retrieve various personal information, including first and last names. I want to change the order that the data is returned by based on a passed parameter, called #p_Code. When #p_Code is 4, I want to order by first name, then last name. If it's not 4, then I want to order by last name, then first name.
I'm working with MS Sql.
Here's the query as it stands:
Select Last,
First,
Phone,
Email
From Master.dbo.Cust
Order by
case #p_Code
when '4' then
([First], [Last])
else
([Last], [First])
end
This should do it:
DECLARE #p_Code VARCHAR(10)
SET #p_Code = '4'
Select [Last],
[First],
Phone,
Email
From Master.dbo.Cust
Order by
case WHEN #p_Code = '4' THEN (RANK() OVER (ORDER BY [First], [Last]))
ELSE (RANK() OVER (ORDER BY [Last],[First] )) END
I don't have a test environment handy, but how about this:
Select Last,
First,
Phone,
Email,
(case #p_Code when '4' then [first] else [last] end) as key1,
(case #p_Code when '4' then [last] else [first] end) as key2
From Master.dbo.Cust
Order by key1, key2
Example: Front Office Manager 0105212000
Only need 10521200, so I am dropping the first and last characters.
Before:
0105212000
After:
10521200
Here's what I came up with so far.
SELECT DISTINCT NAME, right(DESCRIPTION, 9) as 'DESC', DESCRIPTION
FROM LABORLEVELENTRY
WHERE LABORLEVELDEFID = '201'
AND INACTIVE = '0'
ORDER BY NAME
SELECT DISTINCT NAME,
SUBSTRING(DESCRIPTION, 2, LEN(DESCRIPTION)-2) as 'DESC',
DESCRIPTION
FROM LABORLEVELENTRY
WHERE LABORLEVELDEFID = '201'
AND INACTIVE = '0'
ORDER BY NAME
SELECT SUBSTRING ( DESCRIPTION , 2 , LEN(DESCRIPTION)-2 )
Starting on the second character, select everything else but the last character
How about:
select left(right('Front Office Manager 0105212000', 9), 8)
So:
SELECT DISTINCT NAME,
left(right(DESCRIPTION, 9), 8) as 'DESC', DESCRIPTION
FROM LABORLEVELENTRY
WHERE LABORLEVELDEFID = '201'
AND INACTIVE = '0'
ORDER BY NAME