Order by more than clause in a case statement - sql-server

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

Related

CASE WHEN with aggregate functions

I can't understand the purpose of the query using conditional function :"CASE WHEN with aggregate functions"..
1. what is the purpose of the aggregate function in this causes ?
2. what is the difference between putting the aggregate function inside the sentence for example: case when max()..
compared to max(case when...)
Below: find the columns include null values in the table that the rows known.
SELECT *
FROM (
SELECT (CASE WHEN MAX(customer_id) IS NULL THEN 'customer_id' ELSE NULL END ) AS 'Name' FROM customers
UNION ALL
SELECT (CASE WHEN MAX(customer_name) IS NULL THEN 'customer_name' ELSE NULL END ) FROM customers
UNION ALL
SELECT (CASE WHEN MAX(customer_address) IS NULL THEN 'customer_address' ELSE NULL END ) FROM customers
UNION ALL
SELECT (CASE WHEN MAX(customer_age) IS NULL THEN 'customer_age' ELSE NULL END ) FROM customers
) tbl
WHERE tbl.Name IS NOT NULL

How do I select records into a single row?

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;

SQL Error "Conversion failed when converting date and/or time from character string" whereas not converting

With the following query (which contains no string to date and/or time conversion):
SELECT
Date,
RangeFam,
QTY,
Country
FROM (
SELECT Q_QTM as Qty,
Q_OFDFIN as Date,
Q_PAYS as Country,
CASE Q_DTRI05
WHEN 'eBALTIC - EBB' THEN 'EBAB'
WHEN 'Baltic -' THEN 'BALT'
WHEN 'eBALTIC - EBF' THEN 'EBAF'
WHEN 'Roof-tops - ENERGY' THEN 'ENER'
WHEN 'Roof-tops - FLEXAIR' THEN 'FLER'
END as RangeFam
FROM [sales].[dbo].[CARNET2_D]
WHERE Q_OFET='D'
and Q_TYPE='M'
UNION ALL
SELECT Qty,
Range_Code as RangeFam,
ShippingDate as Date,
CASE Country collate DATABASE_DEFAULT
WHEN 'France' THEN 'FRANCE'
WHEN 'Netherlands' THEN 'PAYS BAS'
WHEN 'Belgium' THEN 'BELGIQUE'
WHEN 'Portugal' THEN 'PORTUGAL'
WHEN 'Spain' THEN 'ESPAGNE'
END AS Country
FROM [crmv2].[dbo].[View_Forecastdata_Extended]
WHERE BaseUnit='1'
and (Project_status='Detection / Faisability' or Project_status='Execution' or Project_status='Quotation' or Project_status='Specification stage')
and [Report_S3A/B_group]='Rooftop'
and Sop='1'
and SopValid='1'
and (Sourcing='L&B' or Sourcing='LON' or Sourcing='BUR')
) as T1
ORDER BY Date
I get this error:
Msg 241, Level 16, State 1, Line 1
Conversion failed when converting date and/or time from character string.
Something weird is that if I remove all the code related to the field RangeFam the query is ok so I guess I miss something about it
Thank you
When I say that when I remove the code about RangeFam I mean that there is no problem with the following Query:
SELECT
Date,
--RangeFam,
QTY,
Country
FROM (
SELECT Q_QTM as Qty,
Q_OFDFIN as Date,
Q_PAYS as Country
--CASE Q_DTRI05
-- WHEN 'eBALTIC - EBB' THEN 'EBAB'
-- WHEN 'Baltic -' THEN 'BALT'
-- WHEN 'eBALTIC - EBF' THEN 'EBAF'
-- WHEN 'Roof-tops - ENERGY' THEN 'ENER'
-- WHEN 'Roof-tops - FLEXAIR' THEN 'FLER'
--END as RangeFam
FROM [sales].[dbo].[CARNET2_D]
WHERE Q_OFET='D'
and Q_TYPE='M'
UNION ALL
SELECT Qty,
--Range_Code as RangeFam,
ShippingDate as Date,
CASE Country collate DATABASE_DEFAULT
WHEN 'France' THEN 'FRANCE'
WHEN 'Netherlands' THEN 'PAYS BAS'
WHEN 'Belgium' THEN 'BELGIQUE'
WHEN 'Portugal' THEN 'PORTUGAL'
WHEN 'Spain' THEN 'ESPAGNE'
END AS Country
FROM [crmv2].[dbo].[View_Forecastdata_Extended]
WHERE BaseUnit='1'
and (Project_status='Detection / Faisability' or Project_status='Execution' or Project_status='Quotation' or Project_status='Specification stage')
and [Report_S3A/B_group]='Rooftop'
and Sop='1'
and SopValid='1'
and (Sourcing='L&B' or Sourcing='LON' or Sourcing='BUR')
) as T1
ORDER BY Date
The way the query is written the contents of Q_OFDFIN in the first subquery are UNIONed with the contents of Range_Code in the second one. Since one seems to be a Date and the other a string, the server has to convert them to a common type.
UNION and UNION ALL work on result fields by position, not subquery aliases.
To fix the problem ensure the columns appear in the correct order:
FROM (
SELECT Q_QTM as Qty,
Q_OFDFIN as Date,
Q_PAYS as Country,
CASE Q_DTRI05
WHEN 'eBALTIC - EBB' THEN 'EBAB'
WHEN 'Baltic -' THEN 'BALT'
WHEN 'eBALTIC - EBF' THEN 'EBAF'
WHEN 'Roof-tops - ENERGY' THEN 'ENER'
WHEN 'Roof-tops - FLEXAIR' THEN 'FLER'
END as RangeFam
FROM [sales].[dbo].[CARNET2_D]
WHERE Q_OFET='D'
and Q_TYPE='M'
UNION ALL
SELECT Qty,
ShippingDate as Date,
CASE Country collate DATABASE_DEFAULT
WHEN 'France' THEN 'FRANCE'
WHEN 'Netherlands' THEN 'PAYS BAS'
WHEN 'Belgium' THEN 'BELGIQUE'
WHEN 'Portugal' THEN 'PORTUGAL'
WHEN 'Spain' THEN 'ESPAGNE'
END AS Country,
Range_Code as RangeFam
FROM [crmv2].[dbo].[View_Forecastdata_Extended]
...

Query returns no results

I am running a query that counts emails sent by customers, based on their subject.
DECLARE #LastMonthNo varchar(2)
DECLARE #LastMYear varchar(4)
SET #LastMonthNo = DATEPART(m,DATEADD(m,-1,GetDate()))
SET #LastMYear = DATEPART(yyyy,DATEADD(m,-1,GetDate()));
SELECT
CustID, CustName, CustEmail,
ISNULL(SUM(CASE WHEN EmailSubject LIKE 'KeyWord' THEN 1 END),0) AS TotalEmail
FROM
TableEmails
WHERE
DATEPART(M, DATESENT) = #LastMonthNo
AND DATEPART(YYYY, DATESENT) = #LastYearNo
GROUP BY CustID, CustName, CustEmail
For some customers, the query returns no results. I do not mean NULL, I mean there is no record at all. However, I need to identify those customers.
What can I do to get the query to generate some sort of results? A 0 would be perfect.
Try something like this..
SELECT CustID, CustName, CustEmail,
SUM(CASE WHEN EmailSubject LIKE 'KeyWord'
AND DATEPART(YYYY,DATESENT)=#LastYearNo
AND DATEPART(YYYY,DATESENT)=#LastYearNo
THEN 1 ELSE 0 END) AS TotalEmail,
FROM TableEmails
GROUP BY CustID, CustName, CustEmail
What is the difference?
WHERE part executes before GROUP BY. So, with your query, you are grouping your results after other customers are filtered out. If you move that condition to CASE statement, you will check that condition on each record in the table regardless of dates. Hope that makes sense.

How do I change text data to numeric in SQL Server?

SELECT
a.AccountNumber, a.FirstName, a.LastName, a.Address, a.City, a.State,
a.Zip, a.EmailAddress, a.PhoneNumber, a.LastUpdated, a.LastVisit,
a.TotalSales, a.AccountOpened, a.CustomText4 as StoreCode,
CASE
WHEN (a.CustomText1 IS 'JAN') THEN '1'
END AS DOB,
GETDATE() as Extract_date
FROM
database.dbo.Customer a
CustomText1 column has Month data with a text data.I am trying to convert JAN-DEC to Numeric.
CASE WHEN IS '' isn't working.
"IS" is not a valid expression for CASE statement. Check the online doc, you have a couple ways to do it, this is the simplest way, repeat for the rest of the months.
SELECT DOB =
CASE a.CustomText1
WHEN 'JAN' THEN '1'
WHEN 'FEB' THEN '2'
WHEN 'MAR' THEN '3'
ELSE a.CustomText1
END
FROM database.dbo.Customer a
Greg's answer works, but it's over 12 lines. Here's how to do it in one.
SELECT MONTH(CAST('01' + CustomText1 + '00' AS DATE))
FROM dbo.Customer

Resources