SQL Replace Multiple Values based on one column value - sql

I need to replace results on up to 9 columns based on one other column value.
If the column "role" is the value "SeniorManagement", I want to replace what would be default hierarchical values with hard values.
Here's how I can accomplish this now:
, CASE
WHEN d.Role = 'SeniorManagement'
THEN (Replace(p.Firstname,'John','Joe')) END as First
, CASE
WHEN d.Role = 'SeniorManagement'
THEN (Replace(p.Lastname,'TopDog','AssignedPerson')) END as Last
, CASE...
My question is, is there a less verbose way to combine these?
Pseudo ( I know this doens't work :-)
, CASE
WHEN d.Role = 'SeniorManagement'
THEN (Replace(p.Firstname,'John','Joe')) as First
THEN (Replace(p.Lastname,'TopDog','AssignedPerson')) as Last
THEN (Replace(p.Email,'TopDog#wherever','AssignedPerson#wherever')) as Email
Thanks

what about using a function?
create function dbo.GetColumnValue
(
#ColumnBasedValue varchar(max),
#ColumnToReplace varchar(max), --or the type you want
#ToReplace varchar(max),
#Replacement varchar(max)
)
as
BEGIN
return (select case #ColumnBasedValue when 'SeniorManagement'
then (Replace(#ColumnToReplace,#ToReplace,#Replacement))
else #replaceValue END)
END
and use it like
select dbo.GetColumnValue(d.Role, p.Firstname,'John','Joe') as First,
dbo.GetColumnValue(d.Role, p.Lastname,'TopDog','AssignedPerson') as Last..

Depending on what the context is, you might be able to get away with doing raw selects.
Select d.Role, 'Joe' as First, 'AssignedPerson' as Last
and just filter each select with a where clause.
If you want to do multiple ones, use a union.

Related

T-SQL Skip cte Table and Union when Variable Is Null

I've got a query that captures all shipments and costs from our factory. Sample data and desired output on Google Drive here:
https://drive.google.com/open?id=0B4xdnV0LFZI1VndEaGgxNDVpU2M
The issue is we've got 2 different ways of selling things. One is 'Regluar' where we make it and the other one is a 'buy/sell' where we buy and sell it.
To capture the costs I've had to write two queries, one for each scenario. The end users of this query can enter in a date range and the query works well then, but I'm stuck when it comes to the variable #Job_No.
All work that goes through our factory (cteRegularJobs) has a Job Number associated with it and I've declared a variable so users can use it to search. The cteBuyandSell has a value of 'NULL' for Job_No declared in the SELECT statement so I can do a UNION of these two tables at the end. However, no buy/sell jobs have Job Numbers assigned to them, they are always NULL.
Initially #Job_No is declared as '' and when it's left '' I want the results from both cte tables returned. If there is an entry by the user, i.e. '001' then I want results for cteRegularJobs.
If it makes it easier I am open to declaring the cteBuyandSell.Job_No something else besides NULL, like "Buy and Sell".
The real query is complicated so here's a simplified example of the structure:
DELCARE #Job_No AS varchar(10) = '';
SET #Job_No = {User Input or leave as ''};
WITH
cteBuyandSell AS ( NULL AS 'Job_No',
...),
cteRegularJobs AS (tblJobs.Job_No AS 'Job_No',
...
WHERE tblJobs.Job_No LIKE #Job_No)
SELECT *
FROM
(cteBuyandSell
UNION
cteRegularJobs)
You can logically break this up with an IF statement to check the value of your variable. I'd suggest NULL over white space though. Here's an example procedure... with the limited code you provided.
CREATE PROCEDURE getData(#Job_No varchar(10) = NULL)
AS
IF #Job_No IS NULL
BEGIN
WITH
cteBuyandSell AS ( NULL AS 'Job_No',
...),
cteRegularJobs AS (tblJobs.Job_No AS 'Job_No',
...
WHERE tblJobs.Job_No LIKE #Job_No)
SELECT *
FROM
(cteBuyandSell
UNION
cteRegularJobs)
END
ELSE
BEGIN
WITH
cteRegularJobs AS (tblJobs.Job_No AS 'Job_No',
...
WHERE tblJobs.Job_No LIKE #Job_No)
SELECT * FROM cteRetularJobs
END

Selecting from table to insert into another, getting a type error

I have the following query which inserts data into one table after selecting it from another.
The problem is that the data types do not match for one of the columns. I have simplified the query below.
INSERT INTO tbl.LogTable (
[SelPartNo], -- This does not match, see below
)
SELECT TOP 1
IF([SelPartNo] = 'False', NULL, [SelPartNo],
FROM tbl.MyTable
WHERE ID = '20358'
ORDER BY CreateDate DESC
The first SelPartNo is an int and the second is a VarChar. In most instances the SelPartNo for the second one (tbl.MyTable) is NULL or an integer, which I don't think will cause a problem. But in some cases the value is "False", which needs to return NULL.
I have tried an IF statement but I am doing something wrong because it's giving a syntax error and I am unsure if this is the correct approach.
Your code is syntactically incorect...
Try it with
NULLIF([SelPartNo],'False')
This function returns NULL if the two expressions are equal.
Details: https://msdn.microsoft.com/en-us/library/ms177562.aspx
I don't think IF is a function, at least not one which you can use in a SELECT statement. But CASE WHEN ... END is your friend:
INSERT INTO tbl.LogTable (
[SelPartNo]
)
SELECT TOP 1
CASE WHEN [SelPartNo] = 'False' THEN NULL ELSE [SelPartNo] END
FROM tbl.MyTable
WHERE ID = '20358'
ORDER BY CreateDate DESC

SQL - String Logic

I don't know if what I am wanting to achieve is possible so here is my conundrum.
Within a SQL table there are a number of fields that contain yes/no flags in a string so for example. On the field may be be called 'Stock' and within this one field there is a string of flags which e.g. 'YNYYY' lets say for example that the flags stand for.
Coke
Fanta
Pepsi
Lilt
Dr Pepper
in this instance I would want in my return of data to return Coke,Pepsi,Lilt,Dr Pepper ommiting the Fanta.
Now this would be possible using the CASE Statement and this may be the answer that I have to use, however ideally so I don't have to write hundreds of different variables anyone know of a way this could be achieved?
Your help as always appreciated, I've done the normal googling and maybe I simply don't know what to search for as its giving me blanks.
Please point me in the right direction.
Regards
R
Why dont you use SELECT with WHERE?
Something like this.
SELECT GROUP_CONCAT(`Stock`)
FROM table_name
WHERE `flag` = 'Y'
Hope this helps.
One way you can achieve your goal is by writing a table valued function that turns your Y/N string into a table of (Id INT, value BIT), you could then join to a look up table based on convention. Here's what something like this would look like:
CREATE FUNCTION udf_StringToBool(#intput varchar(100))
RETURNS #table TABLE (
Id INT IDENTITY(1,1),
Value BIT
)
AS
begin
declare #temp_input varchar(100) = #intput
while len(#temp_input) > 0
begin
insert into #table (value)
SELECT CASE LEFT(#temp_input, 1) WHEN 'Y' THEN 1 ELSE 0 END
set #temp_input = right(#temp_input, len(#temp_input)-1)
END
RETURN
end
You would then join your stock (and a lookup to product) table with this function, then remove any that are not in stock in the WHERE clause:
SELECT s.*, v.Value, pl.Name
FROM
stock s
cross apply
(
select b.* from udf_StringToBool(s.Flags) b
) v
join product_lookup pl on pl.Id = v.Id
WHERE v.Value = 1
Here's how you would define the lookup table:
create table product_lookup
(
Id INT IDENTITY(1,1),
Name Varchar(50)
)
insert into product_lookup (Name) values
('Coke'),
('Fanta'),
('Pepsi'),
('Lilt'),
('Dr Pepper')
Then you could use PIVOT to generate the columns with booleans.
In the end I chose to use 'substring' and the 'case' statement so that each item appeared in it's own field this way I mitigated the need to write every variable.
SELECT CASE WHEN SUBSTRING(STOCK,1,1) = 'y' THEN 'IN STOCK' ELSE 'OUTOFSTOCK' END AS COKE
I don't know why it didnt occur to me to begin with and without your prompting and guidance I would have probably done this the long way round as ever thanks to all!

Combine Unique Column Values Into One to Avoid Duplicates

For simplicity, assume I have two tables joined by account#. The second table has two columns, id and comment. Each account could have one or more comments and each unique comment has a unique id.
I need to write a t-sql query to generate one row for each account - which I assume means I need to combine as many comments as might exit for each account. This assumes the result set will only show the account# once. Simple?
Sql Server is a RDBMS best tuned for storing data and retrieving data, you can retrieve the desired data with one very simple query but the desired format should be handled with any of the reporting tools available like ssrs or crystal reports
Your query will be a simple inner join something like this
SELECT A.Account , B.Comment
FROM TableA AS A INNER JOIN TableB AS B
ON A.Account = B.Account
Now you can use your reporting tool to Group all the Comments by Account when Displaying data.
I do agree with M. Ali, but if you don't have that option, the following will work.
SELECT [accountID]
, [name]
, (SELECT CAST(Comment + ', ' AS VARCHAR(MAX))
FROM [comments]
WHERE (accountID = accounts.accountID)
FOR XML PATH ('')
) AS Comments
FROM accounts
SQL Fiddle
In my actual project I have this exact situation.
What you need is a solution to aggregate the comments in order to show only one line per account#.
I solve it by creating a function to concatenate the comments, like this:
create function dbo.aggregateComments( #accountId integer, #separator varchar( 5 ) )
as
begin;
declare #comments varchar( max ); set #comments = '';
select #comments = #comments + #separator + YouCommentsTableName.CommentColumn
from dbo.YouCommentsTableNAme
where YouCommentsTableName.AccountId = #accountId;
return #comments;
end;
You can use it on you query this way:
select account#, dbo.aggretateComments( account#, ',' )
from dbo.YourAccountTableName
Creating a function will give you a common place to retrieve your comments. It's a good programming practice.

How do you query an int column for any value?

How can you query a column for any value in that column? (ie. How do I build a dynamic where clause that can either filter the value, or not.)
I want to be able to query for either a specific value, or not. For instance, I might want the value to be 1, but I might want it to be any number.
Is there a way to use a wild card (like "*"), to match any value, so that it can be dynamically inserted where I want no filter?
For instance:
select int_col from table where int_col = 1 // Query for a specific value
select int_col from table where int_col = * // Query for any value
The reason why I do not want to use 2 separate SQL statements is because I am using this as a SQL Data Source, which can only have 1 select statement.
Sometimes I would query for actual value (like 1, 2...) so I can't not have a condition either.
I take it you want some dynamic behavior on your WHERE clause, without having to dynamically build your WHERE clause.
With a single parameter, you can use ISNULL (or COALESCE) like this:
SELECT * FROM Table WHERE ID = ISNULL(#id, ID)
which allows a NULL parameter to match all. Some prefer the longer but more explicit:
SELECT * FROM Table WHERE (#id IS NULL) OR (ID = #id)
A simple answer would be use: IS NOT NULL. But if you are asking for say 123* for numbers like 123456 or 1234 or 1237 then the you could convert it to a varchar and then test against using standard wild cards.
In your where clause: cast(myIntColumn as varchar(15)) like '123%'.
Assuming the value you're filtering on is a parameter in a stored procedure, or contained in a variable called #Value, you can do it like this:
select * from table where #Value is null or intCol = #Value
If #Value is null then the or part of the clause is ignored, so the query won't filter on intCol.
The equivalent of wildcards for numbers are the comparators.
So, if you wanted to find all positive integers:
select int_col from table where int_col > 0
any numbers between a hundred and a thousand:
select int_col from table where int_col BETWEEN 100 AND 1000
and so on.
I don't quite understand what you're asking. I think you should use two different queries for the different situations you have.
When you're not looking for a specific value:
SELECT * FROM table
When you are looking for a specific value:
SELECT * FROM table WHERE intcol = 1
You can use the parameter as a wildcard by assigning special meaning to NULL:
DECLARE #q INT = 1
SELECT * FROM table WHERE IntegerColumn = #q OR #q IS NULL
This way, when you pass in NULL; you get all rows.
If NULL is a valid value to query for, then you need to use two parameters.
If you really want the value of your column for all rows on the table you can simply use
select int_col
from table
If you want to know all the distinct values, but don't care how many times they're repeated you can use
select distinct int_col
from table
And if you want to know all the distinct values and how many times they each appear, use
select int_col, count(*)
from table
group by int_col
To have the values sorted properly you can add
order by int_col
to all the queries above.
Share and enjoy.