Given the two column below how can I select the row 110-118 if my filter is 111? 100-118 is a range thus 111 falls between 100-118
Dest_ZIP Ground
004-005 003
009 005
068-089 002
100-118 001
Below is a simple example of how to do this in SQL using a sub query to get the start and end range. This can be expanded on to better handle parsing the string value.
Declare #Temp TABLE
(
Dest_Zip varchar(7),
Ground varchar(3)
)
INSERT INTO #Temp VALUES ('004-005','003')
INSERT INTO #Temp VALUES ('068-089','002')
INSERT INTO #Temp VALUES ('100-118','001')
SELECT A.Dest_Zip, A.Ground FROM
(
select
Convert(int, SUBSTRING(Dest_Zip,1,3)) StartNum,
Convert(int, SUBSTRING(Dest_Zip,5,3)) EndNum,
*
from #Temp
) AS A
WHERE 111 >= A.StartNum AND 111 <= A.EndNum
Fix the data. Here is a simple way using computed columns (and assuming the "zips" are always 3 characters):
alter table t
add column minzip as (left(dest_zip), 3),
add column maxzip as (right(dest_zip), 3);
Then, you can run the query as:
select t.*
from t
where '111' between t.minzip and t.maxzip;
You can even create an index on computed columns, which can help performance (although not much in this case).
If you wish to make the checks in php, maybe this sample code can help you:
<?php
$my_string = "111";
$foo = "100-118"; // our range
$bar = explode('-', $foo); // Get an array .. let's call it $bar
// Print the output, see how the array looks
//print_r($bar);
//echo $bar[0].'<br />';
//echo $bar[1].'<br />';
if(($bar[0] <= $my_string ) AND ($bar[1] >= $my_string)){ echo 'true';} else { echo 'false';}
?>
Related
I have a procedure that needs to handle up to 60 different variables.
The variables have a standardized naming convention.
#TextParameter1 varchar(443) = NULL,
#TextParameter2 varchar(443) = NULL,
#TextParameter3 varchar(443) = NULL
I need to be able to check which variables are NULL and which aren't, and then handle the values of the non-null variables.
I tried using dynamic SQL to iterate over the variables by making the first portion of the variable name a string and iterating through the numbers on the end.
declare #rownum int = 1
while #rownum <= 60
declare #var_sql nvarchar(max) = 'INSERT INTO #slicer
SELECT IDENTITY(Int, 1, 1) AS rowkey, value
FROM STRING_SPLIT(CAST(#DetailQueryTextParameter' + CAST(#rownum AS nvarchar(3)) AS varchar(4000)), '^')'
execute #var_sql
Set #rownum = #rownum + 1
This will return an error claiming that #DetailQueryTextParameter needs to be declared first. What is the best way to handle all of these variables? I could do by writing a line of code for every single variable, but it seems like there is a better way. Can I insert the variable names into a table and iterate from there?
(The below was updated to include the SPLIT_STRING().)
You can use a VALUES subselect (not sure if that is the proper term) to combine all of your parameters into a single collection. You can then filter out the null values and pass the remaining values into STRING_SPLIT() using a CROSS APPLY.
DECLARE
#TextParameter1 varchar(443) = NULL,
#TextParameter2 varchar(443) = 'aaa^bbb',
#TextParameter3 varchar(443) = NULL,
#TextParameter4 varchar(443) = 'xxx^yyy^zzz',
#TextParameter5 varchar(443) = NULL
SELECT A.*, B.Value AS SplitValue
FROM (
VALUES
(1, #TextParameter1),
(2, #TextParameter2),
(3, #TextParameter3),
(4, #TextParameter4),
(5, #TextParameter5)
) A(Parameter, Value)
CROSS APPLY STRING_SPLIT(A.Value, '^') B
WHERE A.Value IS NOT NULL
Which would yield results like:
Parameter
Value
SplitValue
2
aaa^bbb
aaa
2
aaa^bbb
bbb
4
xxx^yyy^zzz
xxx
4
xxx^yyy^zzz
yyy
4
xxx^yyy^zzz
zzz
See this db<>fiddle.
I have prices coming in my source file like below -
78-22¼,
78-18⅝
I need to calculate these price. For example for first case result should be 78-22.25. I searched a lot but found that SQL supports few of these characters only. Is there anyway to make sure we are able to calculate for whatever value we are getting. Solution in either SQL or PowerShell could work.
You could write a PowerShell function to convert the fractions to decimals:
PS ~> ConvertTo-Decimal '18⅝'
18.625
To do so, we'll need to write a function that:
Uses regex to identify and extract the integer and fraction parts
Uses [char]::GetNumericValue() to get the decimal representation of the fraction
Outputs the sum of the two
function ConvertTo-Decimal {
param(
[Parameter(Mandatory)]
[string]$InputObject
)
if($InputObject -match '^(-?)(\d+)(\p{No})?$'){
$baseValue = +$Matches[2]
if($Matches[3]){
$baseValue += [char]::GetNumericValue($Matches[3])
}
if($Matches[1] -eq '-'){
$baseValue *= -1
}
return $baseValue
}
return 0
}
Hoo this one was fun.
If you want to do it purley in TSQL give this a tug:
DECLARE #table TABLE (Glyph NVARCHAR(2), Dec DECIMAL(8,6))
INSERT INTO #table (Glyph, Dec) VALUES
(N'¼', 1.0/4),(N'½', 1.0/2),(N'¾', 3.0/4),(N'⅐', 1.0/7),
(N'⅑', 1.0/8),(N'⅒',1.0/10),(N'⅓', 1.0/3),(N'⅔', 2.0/3),
(N'⅕', 1.0/5),(N'⅖', 2.0/5),(N'⅗', 3.0/5),(N'⅘', 4.0/5),
(N'⅙', 1.0/6),(N'⅚', 5.0/6),(N'⅛', 1.0/8),(N'⅜', 3.0/8),
(N'⅝', 5.0/8),(N'⅞', 7.0/8),(N'⅟', 1.0/1)
DECLARE #values TABLE (ID INT IDENTITY, value NVARCHAR(20))
INSERT INTO #values (value) VALUES
(N'78-22¼'),(N'78-18⅝'),(N'10+1')
;WITH sort AS (
SELECT v.*, t.*,
CASE WHEN m.value = v.value THEN
CASE WHEN t.Dec IS NOT NULL THEN REPLACE(p.value,t.Glyph,'')+dec
ELSE p.value
END
ELSE
CASE WHEN t.Dec IS NOT NULL THEN REPLACE(m.value,t.Glyph,'')+dec
ELSE m.value
END
END AS v,
CASE WHEN m.value = v.value THEN '+'
ELSE '-' END AS op,
ROW_NUMBER() OVER (PARTITION BY v.value ORDER BY CASE WHEN m.value = v.value THEN CHARINDEX(m.value,v.value) ELSE CHARINDEX(p.value,v.value) END) AS subID
FROM #values v
OUTER APPLY STRING_SPLIT(v.value,'-') m
OUTER APPLY STRING_SPLIT(v.value,'+') p
LEFT OUTER JOIN #table t
ON RIGHT(CASE WHEN m.value = v.value THEN p.value ELSE m.value END,1) = t.Glyph
)
SELECT ID, value, SUM(v * CASE WHEN subId = 1 THEN 1 WHEN op = '+' THEN 1 ELSE -1 END) AS v
FROM sort
GROUP BY ID, value
ID value v
---------------------
1 78-22¼ 55.750000
2 78-18⅝ 59.375000
3 10+1 11.000000
#values replaces your table.
disclaimer: this works, it'll probably perform like hot garbage, but it works :P
In T-SQL you could write a function like this that takes a vulgar fraction and replaces it with its decimal equivalent (this is not completely exhaustive, but handles the most common fractions, and makes a guess about whether you want .666 or .667 or something else for ⅔):
CREATE FUNCTION dbo.FractionToDecimal(#str nvarchar(255))
RETURNS TABLE
AS
RETURN
(
SELECT str = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
REPLACE(REPLACE(REPLACE(REPLACE(#str, N'¼','.25'),
N'½','.5'), N'¾','.75'), N'⅓','.333'), N'⅔','.666'),
N'⅛','.125'), N'⅜','.375'), N'⅝','.625'), N'⅞','.875')
);
Sample usage:
DECLARE #x table(str nvarchar(255));
INSERT #x VALUES(N'78-22¼'),(N'78-18⅝');
SELECT [input] = i.str, [output] = o.str
FROM #x AS i
CROSS APPLY dbo.FractionToDecimal(str) AS o;
Output:
input
output
78-22¼
78-22.25
78-18⅝
78-18.625
Working example in this fiddle.
Note there are only so many fraction codes available that you could be pulling in ... so you could add any to the above e.g. from this set but it isn't the case that you would have to handle any possible fraction, only the ones that are represented by these specific symbols. If someone passes in plain text 9/10 or 31/33 that is a completely different problem space than what you have outlined in the question.
I have an issue where I am trying to add a leading 0 to run an output.
SELECT
CASE
WHEN LEN(t.trans_time) = 5
THEN CONCAT(0, [trans_time])
ELSE T.[trans_time]
END AS [TransactionTime]
,RIGHT(CONCAT(0,trans_time),6) AS trans_time
,LEN(T.trans_Time)
,t.trans_time
Why does the case statement not return the leading 0 whereas using:
,RIGHT(CONCAT(0,trans_time),6) AS trans_time
Works no problem.
Case expression return only one type, whereas concat() would return different type & i am assuming trans_time has INT type.
So, you would need to do type conversations :
SELECT (CASE WHEN LEN(t.trans_time) = 5
THEN CONCAT(0, [trans_time])
ELSE CAST(T.[trans_time] AS VARCHAR(255))
END) AS [TransactionTime],
. . .
Another way to do this is to use the format function, wich is available from sql server 2012.
It not only makes the code more readable but will also perform better.
declare #t table (id int)
insert into #t values (90113), (90204), (90207), (90235), (90302), (90318), (90324)
select format(id, '000000') as TransactionTime from #t
this will return
TransactionTime
---------------
090113
090204
090207
090235
090302
090318
090324
I'm trying to create a set of flags based off of a column of character strings in a data set. The string has thousands of unique values, but I want to create flags for only a small subset (say 10). I'd like to use a SAS macro variable to do this. I've tried many different approaches, none of which have worked. Here is the code that seems simplest and most logical to me, although it's still not working:
%let Px1='12345';
PROC SQL;
CREATE TABLE CLAIM1 AS
SELECT
b.MEMBERID
, b.ENROL_MN
, CASE WHEN (a.PROCEDURE = &Px1.) THEN 1 ELSE 0 END AS CPT_+&Px1.
, a.DX1
, a.DX2
, a.DX3
, a.DX4
FROM ENROLLMENT as b
left join CLAIMS as a
on a.MEMBERID = b.MEMBERID;
QUIT;
Obviously there is only one flag in this code, but once I figure it out the idea is that I would add additional macro variables and flags. Here is the error message I get:
8048 , CASE WHEN (PROCEDURE= &Px1.) THEN 1 ELSE 0 END AS CPT_+&Px1.
-
78
ERROR 78-322: Expecting a ','.
It seems that the cause of the problem is related to combining the string CPT_ with the macro variable. As I mentioned, I've tried several approaches to addressing this, but none have worked.
Thanks in advance for your help.
Something like this normally requires dynamic sql (although I am not sure how will that works with SAS, I believe it may depend on how you have established connection with the database).
Proc sql;
DECLARE #px1 varchar(20) = '12345'
,#sql varhcar(max) =
'SELECT b.MEMBERID
, b.ENROL_MN
, CASE WHEN (a.PROCEDURE = ' + #Px1 + ') THEN 1 ELSE 0
END AS CPT_' + #px1 + '
, a.DX1
, a.DX2
, a.DX3
, a.DX4
FROM ENROLLMENT as b
left join CLAIMS as a
on a.MEMBERID = b.MEMBERID'
EXEC sp_excutesql #sql;
QUIT;
Your issue here is the quotes in the macro variable.
%let Px1='12345';
So now SAS is seeing this:
... THEN 1 ELSE 0 END AS CPT_+'12345'
That's not remotely legal! You need to remove the '.
%let Px1 = 12345;
Then add back on at the right spot.
CASE WHEN a.procedure = "&px1." THEN 1 ELSE 0 END AS CPT_&px1.
Note " not ' as that lets the macro variable resolve.
If you have a list it might help to put the list into a table. Then you can use SAS code to generate the code to make the flag variables instead of macro code.
Say a table with PX code variable.
data pxlist;
input px $10. ;
cards;
12345
4567
;
You could then use PROC SQL query to generate code to make the flag variable into a macro variable.
proc sql noprint;
select catx(' ','PROCEDURE=',quote(trim(px)),'as',cats('CPT_',px))
into :flags separated by ','
from pxlist
;
%put &=flags;
quit;
Code looks like
PROCEDURE= "12345" as CPT_12345,PROCEDURE= "4567" as CPT_4567
So if we make some dummy data.
data enrollment ;
length memberid $8 enrol_mn $6 ;
input memberid enrol_nm;
cards;
1 201612
;
data claims;
length memberid $8 procedure $10 dx1-dx4 $10 ;
input memberid--dx4 ;
cards;
1 12345 1 2 . . .
1 345 1 2 3 . .
;
We can then combine the two tables and create the flag variables.
proc sql noprint;
create table want as
select *,&flags
from ENROLLMENT
natural join CLAIMS
;
quit;
Results
memberid procedure dx1 dx2 dx3 dx4 enrol_mn CPT_12345 CPT_4567
1 12345 1 2 201612 1 0
1 345 1 2 3 201612 0 0
<pre>update d
set d.Price = null
from dbo.SalDocumentDetail d
left join dbo.StkWarehouse w on w.WarehouseID = d.WarehouseID
where DocumentID=" + 1 + "
and DocumentTypeID=" + 2 + "
and FiscalYear= " + 2016 + "
and isnull(isPrescription,0) <>1
and w.POSType is null
and ProductName BETWEEN ''C' 'AND' 'M''
and Country LIKE ''%land%'''</pre>
Actually this string is only a sample one my original string is very large . i am not getting a point that if i break this string than how many variables i have to make to capture the data also after splitting the string i want that to be inserted into data table containing columns as Felid and Value?
I want my result like :
<pre>
Felid Value
DocumentID= 1
DocumentTypeID= 2
FiscalYear= 2016
isnull(isPrescription,0) <>= 1
w.POSType is= null
ProductName= C
ProductName= M
Country= land
</pre>
<pre>I Use this function but this function split 'and' not split like what i want in my result i want split 'and,or,like,is,between ' if function find any this split it to two columns (Felid and Value)</pre>
<pre>ALTER FUNCTION [dbo].[fnSplitString]
(#List NVARCHAR(MAX),#Delimiter NVARCHAR(255))
RETURNS #Items TABLE(Felid NVARCHAR(Max),Valu nvarchar(MAx))
WITH SCHEMABINDING
AS BEGIN
DECLARE #ll INT=LEN(#List)+1,#ld INT=LEN(#Delimiter);
WITH a AS
(SELECT
[end]=COALESCE(NULLIF(CHARINDEX(#Delimiter,#List,1),0),#ll),
[VlaueFelid]=SUBSTRING(#List,(select
CHARINDEX('where',#List)+5),COALESCE(NULLIF(CHARINDEX('=', #List,0),0),#ll) ) ,
[Value]=SUBSTRING(#List,(select CHARINDEX('="',#List)+2),(select CHARINDEX('and',#List))-(select C`enter code here`HARINDEX('="',#List)+3))
UNION ALL
SELECT
[end]=COALESCE(NULLIF(CHARINDEX(#Delimiter,#List,[end]+#ld), 0),#ll),
[VlaueFelid]=SUBSTRING(#List,[end]+#ld, COALESCE(NULLIF(CHARINDEX('=',#List, [end]+#ld),0),#ll)-[end]-#ld),
[Value]=SUBSTRING(#List,[end]+#ld+16, COALESCE(NULLIF(CHARINDEX('=',#List,[end]+#ld),0),#ll)-[end]-#ld-5)
FROM a WHERE [end]< #ll) INSERT #Items SELECT[VlaueFelid],[Value] FROM a WHERE LEN([VlaueFelid])>0 RETURN;
END</pre>