Convert CHAR to NUMERIC in SQL - sql-server

I am trying to set up a database that has the following columns, "number", "full names", "card no", "status". In the last column status there are many types of status, which I would like to have them converted to 0 or 1 to another column within the table, depending on the statuses. The database then, is to be pulled to another application and will use the binary column to give access to a facility.
I have not tried any code on this, still learning.
SELECT TOP 1000 [MemberNo]
,[FirstName]
,[LastName]
,[CardNo]
,[Status]
FROM [GateAccess].[dbo].[GateProxy]

Not sure why ask a question when you havent tried anything...
First you are trying to create a table with following columns not a database.
Here is a link of how to create a table http://www.mysqltutorial.org/mysql-create-table/
Second you dont really need to to convert char to numeric I would personally use CASE
here is a link on case https://www.techonthenet.com/mysql/functions/case.php
Regarding to your 'application and will use the binary column to give access to a facility' it depends on what application is pulling the data.

This may help ...
DECLARE #sampletext VARCHAR(100) = '123456';
SELECT TRY_CONVERT(INT, #sampletext); -- 123456
SELECT TRY_CAST(#sampletext AS INT); -- 123456
SELECT TOP 1000 [MemberNo]
,[FirstName]
,[LastName]
,[CardNo]
,[Status]
-- Try like this for new derived column
,CASE WHEN [Status] = 'yourValue'THEN 1
WHEN [Status] = 'yourOtherValue' THEN 0
END
FROM [GateAccess].[dbo].[GateProxy]

Related

not able to identify difference between same value

I have data inside a table's column. I SELECT DISTINCT of that column, i also put LTRIM(RTRIM(col_name)) as well while writing SELECT. But still I am getting duplicate column record.
How can we identify why it is happening and how we can avoid it?
I tried RTRIM, LTRIM, UPPER function. Still no help.
Query:
select distinct LTRIM(RTRIM(serverstatus))
from SQLInventory
Output:
Development
Staging
Test
Pre-Production
UNKNOWN
NULL
Need to be decommissioned
Production
Pre-Produc​tion
Decommissioned
Non-Production
Unsupported Edition
Looks like there's a unicode character in there, somewhere. I copied and pasted the values out initially as a varchar, and did the following:
SELECT DISTINCT serverstatus
FROM (VALUES('Development'),
('Staging'),
('Test'),
('Pre-Production'),
('UNKNOWN'),
('NULL'),
('Need to be decommissioned'),
('Production'),
(''),
('Pre-Produc​tion'),
('Decommissioned'),
('Non-Production'),
('Unsupported Edition'))V(serverstatus);
This, interestingly, returned the values below:
Development
Staging
Test
Pre-Production
UNKNOWN
NULL
Need to be decommissioned
Production
Pre-Produc?tion
Decommissioned
Non-Production
Unsupported Edition
Note that one of the values is Pre-Produc?tion, meaning that there is a unicode character between the c and t.
So, let's find out what it is:
SELECT 'Pre-Produc​tion', N'Pre-Produc​tion',
UNICODE(SUBSTRING(N'Pre-Produc​tion',11,1));
The UNICODE function returns back 8203, which is a zero-width space. I assume you want to remove these, so you can update your data by doing:
UPDATE SQLInventory
SET serverstatus = REPLACE(serverstatus, NCHAR(8203), N'');
Now your first query should work as you expect.
(I also suggest you might therefore want a lookup table for your status' with a foreign key, so that this can't happen again).
DB<>fiddle
I deal with this type of thing all the time. For stuff like this NGrams8K and PatReplace8k and PATINDEX are your best friends.
Putting what you posted in a table variable we can analyze the problem:
DECLARE #table TABLE (txtID INT IDENTITY, txt NVARCHAR(100));
INSERT #table (txt)
VALUES ('Development'),('Staging'),('Test'),('Pre-Production'),('UNKNOWN'),(NULL),
('Need to be decommissioned'),('Production'),(''),('Pre-Produc​tion'),('Decommissioned'),
('Non-Production'),('Unsupported Edition');
This query will identify items with characters other than A-Z, spaces and hyphens:
SELECT t.txtID, t.txt
FROM #table AS t
WHERE PATINDEX('%[^a-zA-Z -]%',t.txt) > 0;
This returns:
txtID txt
----------- -------------------------------------------
10 Pre-Produc​tion
To identify the bad character we can use NGrams8k like this:
SELECT t.txtID, t.txt, ng.position, ng.token -- ,UNICODE(ng.token)
FROM #table AS t
CROSS APPLY dbo.NGrams8K(t.txt,1) AS ng
WHERE PATINDEX('%[^a-zA-Z -]%',ng.token)>0;
Which returns:
txtID txt position token
------ ----------------- -------------------- ---------
10 Pre-Produc​tion 11 ?
PatReplace8K makes cleaning up stuff like this quite easily and quickly. First note this query:
SELECT OldString = t.txt, p.NewString
FROM #table AS t
CROSS APPLY dbo.patReplace8K(t.txt,'%[^a-zA-Z -]%','') AS p
WHERE PATINDEX('%[^a-zA-Z -]%',t.txt) > 0;
Which returns this on my system:
OldString NewString
------------------ ----------------
Pre-Produc?tion Pre-Production
To fix the problem you can use patreplace8K like this:
UPDATE t
SET txt = p.newString
FROM #table AS t
CROSS APPLY dbo.patReplace8K(t.txt,'%[^a-zA-Z -]%','') AS p
WHERE PATINDEX('%[^a-zA-Z -]%',t.txt) > 0;

SSRS multiple single cells

I am trying to figure out best way to add multiple fields to a SSRS report.
Report has some plots and tablix which are populated from queries but now I have been asked to add a table with ~20 values. The problem is that I need to have them in a specific order/layout (that I cannot obtain by sorting) and they might need to have a description added above which will be static text (not from the DB).
I would like to avoid situation where I keep 20 copy of the same query which returns single cell where the only difference would be in:
WHERE myTable.partID = xxxx
Any chance I could keep a single query which takes that string like a parameter which I could specify somehow via expression or by any other means?
Not a classical SSRS parameter as I need a different one for each cell...
Or will I need to create 20 queries to fetch all those single values and then put them as separate textfields on the report?
When I've done this in the past, I build a single query that gets all the data I need with some kind of key.
For example I might have a list of captions and values, one per row, that I need to display as part of a report page. The dataset query might look something like ...
DECLARE #t TABLE(Key varchar(20), Amount float, Caption varchar(100))
INSERT INTO #t
SELECT 'TotalSales', SUM(Amount), NULL AS Amount FROM myTable WHERE CountryID = #CountryID
UNION
SELECT 'Currency', NULL, CurrencyCode FROM myCurrencyTable WHERE CountryID = #CountryID
UNION
SELECT 'Population', Population, NULL FROM myPopualtionTable WHERE CountryID = #CountryID
SELECT * FROM #t
The resulting dataset would look like this.
Key Amount Caption
'TotalSales' 12345 NULL
'Currency' NULL 'GBP'
'Population' 62.3 NULL
Lets say we call this dataset dsStuff then in each cell/textbox the xpression would simply be something like.
=LOOKUP("Population", Fields!Key.Value, Fields!Amount.Value, "dsStuff")
or
=LOOKUP("Currency", Fields!Key.Value, Fields!Caption.Value, "dsStuff")

SQL Server - pattern matching a string

First post here. What a great resource. Hoping someone can help....
I have a character field that contains mostly numeric values but not all. The field, lets call it diag, is formatted as varchar(8). It contains diagnosis codes and they have been entered inconsistently at times. So I might see 29001 in the diag field. Or I might see 290.001. Sometimes people will code it as 290.00 other times 29000 and yet other times 290. To make it more complicated, I may have alpha characters in that field so the field could contain something like V700.00 or H601. Using these as examples, but it's indicative of what's in the field.
I am trying to find a range of values....for instance diagnosis codes between 29001 to 29999. Taking into account the inconsistencies in coding entry, I also want to return any records that have a diag value of 290.01 to 299.99 I am just at a loss. Searched here for hours and found a lot of info... but couldn't seem to answer my question. I am somewhat new to SQL and can't figure out how to return records that match the range of values I am looking for. There are 40-some million records so it is a lot of data. Trying to pare it down to something I can work with. I am using an older version of SQL Server...2005 in case it matters.
Any help would be most appreciated. I really don't even know where to start.
Thank you!
you can use this T-SQL to remove all non wanted characters in your numbers.
declare #strText varchar(50)
--set #strText = '23,112'
--set #strText = '23Ass112'
set #strText = '2.3.1.1.2'
WHILE PATINDEX('%[^0-9]%', #strText) > 0
BEGIN
SET #strText = STUFF(#strText, PATINDEX('%[^0-9]%', #strText), 1, '')
END
select #strText
on your case I suggest you to create a function
CREATE Function CleanNumbers(#strText VARCHAR(1000))
RETURNS VARCHAR(1000)
AS
WHILE PATINDEX('%[^0-9]%', #strText) > 0
BEGIN
SET #strText = STUFF(#strText, PATINDEX('%[^0-9]%', #strText), 1, '')
END
return #strText
END
Then you'll have to create a normal query calling the function.
WITH CTE as
(
SELECT dbo.CleanNumbers(yourtable.YourFakeNumber) as Number, yourtable.*
FROM yourtable
WHERE YourCriteria = 1
)
Select * from CTE where CAST(Number as int) between 29001 and 29999
Or easier
Select * from yourtable where CAST(dbo.CleanNumbers(YourFakeNumber) as int) between 29001 and 29999
I hope I haven't done any spelling mistakes ;)
It sounds like you have a little bit of a mess. If you know the rules for the variances, then you could build an automated script to update. But it sounds like it's pretty loose, so you might want to start by deciding what are valid values for the fields, making a table of them to validate against, and then identifying and classifying the invalid data.
First step, you need to get a list of valid diagnosis codes and get them into a table. Something like:
CREATE TABLE [dbo].[DiagnosticCodes](
[DiagnosticCode] [varchar](8) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
[DiagnosticDescription] [varchar](255) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
CONSTRAINT [PK_DiagnosticCodes] PRIMARY KEY CLUSTERED
(
[DiagnosticCode] ASC
)
)
Then get a list of the valid codes and import them into this table.
Then you need to find data in your table that is invalid. Something like this query will give you all the invalid codes in your database:
CREATE TABLE [dbo].[DiagnosticCodesMapping](
[Diag] [varchar](8) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
[NewCode] [varchar](8) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
CONSTRAINT [PK_DiagnosticCodesMapping] PRIMARY KEY CLUSTERED
(
[Diag] ASC
)
)
insert into [dbo].[DiagnosticCodesMapping]
Select distinct MyDataTable.Diag, null NewCode
from MyDataTable
left join DiagnosticCodes
on MyDataTable.Diag = DiagnosticCodes.DiagnosticCode
where DiagnosticCodes.DiagnosticCode is null
This creates a table of all the invalid codes and also includes a field called NewCode, which you will populate a mapping from the invalid code to a new valid code. Hopefully this list will not be ridiculously long. Then you hand it over to someone for review and to enter the NewCode field to be one of the valid codes. Once you have your DiagnosticCodesMapping table completely filled in, you can then do an update to get all your fields to have valid codes:
update MyDataTable
set Diag=NewCode
from MyDataTable
join DiagnosticCodesMapping
where MyDataTable.Diag = DiagnosticCodesMapping.Diag
Doing it this way has the added advantage that you can now start validating all data entry in the future and you'll never have to do this cleanup again. You can create a constraint that ensures only valid codes from the DiagnosticCode table can be entered into the Diag field of your data table. You should check your interface to use the new lookup table as well. You'll also have to create a data maintenance interface to the DiagnosticCode table if you need to have super users with the ability to add new codes.

SQL Server : Select ... From with FULL JOIN with a Default value for a column

I created a table, tblNewParts with 3 columns:
NewCustPart
AddedDate
Handled
and I am trying to FULL JOIN it to an existing table, tblPartsWorkedOn.
tblNewParts is defined to have Handled defaulted to 'N'...
SELECT *
FROM dbo.tblPartsWorkedOn AS BASE
FULL JOIN dbo.tblNewParts AS ADDON ON BASE.[CustPN] = ADDON.[NewCustPart]
WHERE ADDON.[Handled] IS NULL
ORDER BY [CustPN] DESC
And I want the field [Handled] to come back as 'N' instead of NULL when I run the query. The problem is that when there aren't any records in the new table, I get NULL's instead of 'N's.
I saw a SELECT CASE WHEN col1 IS NULL THEN defaultval ELSE col1 END as a mostly suitable answer from here. I am wondering if this will work in this instance, and how would I write that in T-SQL for SQL Server 2012? I need all of the columns from both tables, rather than just the one.
I'm making this a question, rather than a comment on the cited link, so as to not obscure the original link's question.
Thank you for helping!
Name the column (alias.column_name) in select statement and use ISNULL(alias.column,'N').
Thanks
After many iterations I found the answer, it's kind of bulky but here it is anyway. Synopsis:
Yes, the CASE statement does work, but it gives the output as an unnamed column. Also, in this instance to get all of the original columns AND the corrected column, I had to use SELECT *, CASE...END as [ColumnName].
But, here is the better solution, as it will place the information into the correct column, rather than adding a column to the end of the table and calling that column 'Unnamed Column'.
Select [ID], [Seq], [Shipped], [InternalPN], [CustPN], [Line], [Status],
CASE WHEN ADDON.[NewCustPart] IS NULL THEN BASE.[CustPN] ELSE
ADDON.[NewCustomerPart] END as [NewCustPart],
GetDate() as [AddedDate],
CASE WHEN ADDON.[Handled] IS NULL THEN 'N' ELSE ADDON.[Handled] END as [Handled]
from dbo.tblPartsWorkedOn as BASE
full join dbo.tblNewParts as AddOn ON Base.[CustPN] = AddOn.NewCustPart
where AddOn.Handled = 'N' or AddOn.Handled is null
order by [NewCustPart] desc
This sql code places the [CustPN] into [NewCustPart] if it's null, it puts a 'N' into the field [Handled] if it's null and it assigns the date to the [AddedDate] field. It also only returns records that have not been handled, so that you get the ones that need to be looked at; and it orders the resulting output by the [NewCustPart] field value.
Resulting Output looks something like this: (I shortened the DateTime for the output here.)
[ID] [SEQ] [Shipped] [InternalPN] [CustPN] [Status] [NewCustPart] [AddedDate] [Handled]
1 12 N 10012A 10012A UP 10012A 04/02/2016 N
...
Rather than with the nulls:
[ID] [SEQ] [Shipped] [InternalPN] [CustPN] [Status] [NewCustPart] [AddedDate] [Handled]
1 12 N 10012A 10012A UP NULL NULL NULL
...
I'm leaving this up, and just answering it rather than deleting it, because I am fairly sure that someone else will eventually ask this same question. I think that lots of examples showing how and why something is done, is a very helpful thing to have as not everything can be generalized. Just some thoughts and I hope that this helps someone else!

Select All as default value for Multivalue parameter

I'm building a report in Visual Studio 2008 with a lot of multivalue parameters and it's working great, but I would like to have have the "(Select all)" option as the default value when the report is opened.
Is there some kind of expression or SQL code I can use to make this happen? Or do I need to choose "(Select all)" every time, in every parameter, each time I want to run the report?
Try setting the parameters' "default value" to use the same query as the "available values". In effect it provides every single "available value" as a "default value" and the "Select All" option is automatically checked.
Using dataset with default values is one way, but you must use query for Available values and for Default Values, if values are hard coded in Available values tab, then you must define default values as expressions. Pictures should explain everything
Create Parameter (if not automaticly created)
Define values - wrong way example
Define values - correct way example
Set default values - you must define all default values reflecting available values to make "Select All" by default, if you won't define all only those defined will be selected by default.
The Result
One picture for Data type: Int
Does not work if you have nulls.
You can get around this by modifying your select statement to plop something into nulls:
phonenumber = CASE
WHEN (isnull(phonenumber, '')='') THEN '(blank)'
ELSE phonenumber
END
The accepted answer is correct, but not complete.
In order for Select All to be the default option, the Available Values dataset must contain at least 2 columns: value and label. They can return the same data, but their names have to be different. The Default Values dataset will then use value column and then Select All will be the default value. If the dataset returns only 1 column, only the last record's value will be selected in the drop down of the parameter.
Adding to the answer from E_8.
This does not work if you have empty strings.
You can get around this by modifying your select statement in SQL or modifying your query in the SSRS dataset.
Select distinct phonenumber
from YourTable
where phonenumber <> ''
Order by Phonenumber
It works better
CREATE TABLE [dbo].[T_Status](
[Status] [nvarchar](20) NULL
) ON [PRIMARY]
GO
INSERT [dbo].[T_Status] ([Status]) VALUES (N'Active')
GO
INSERT [dbo].[T_Status] ([Status]) VALUES (N'notActive')
GO
INSERT [dbo].[T_Status] ([Status]) VALUES (N'Active')
GO
DECLARE #GetStatus nvarchar(20) = null
--DECLARE #GetStatus nvarchar(20) = 'Active'
SELECT [Status]
FROM [T_Status]
WHERE [Status] = CASE WHEN (isnull(#GetStatus, '')='') THEN [Status]
ELSE #GetStatus END
This is rather easy to achieve by making a dataset with a text-query like this:
SELECT 'Item1'
UNION
SELECT 'Item2'
UNION
SELECT 'Item3'
UNION
SELECT 'Item4'
UNION
SELECT 'ItemN'
The query should return all items that can be selected.

Resources