Ignore leading zeros in JOIN condition? - abap

I want to compare the field bseg~zuonr with aufk~aufnr in an inner join SQL select.
SELECT bseg~hkont, bseg~zuonr, bseg~belnr, bseg~gjahr, aufk~prctr FROM bseg INNER JOIN aufk
ON bseg~zuonr = aufk~aufnr "<--
WHERE bseg~hkont IN #s_hkont
INTO TABLE #DATA(output).
This select is not working right for me and not giving back any data.
I think my problem is, that aufk~aufnr has leading zeros (for example: 000072667023) and bseg~zuonr contains only the number without leading zeros (for example: 72667023).
I have tried to use the TRIM-function inside the SQL select but that did not worked for me (Code snipped: ON bseg~zuonr = TRIM( LEADING '0' FROM aufk~aufnr ) → "(" is not allowed here. "." is expected.)
Did I do something wrong? Do you know any solution for this issue?

You could use the concat function. For example
SELECT bseg~hkont, bseg~zuonr, bseg~belnr, bseg~gjahr, aufk~prctr
FROM bseg
JOIN aufk ON concat( '0000', bseg~zuonr ) = aufk~aufnr
WHERE bseg~hkont IN #s_hkont
INTO TABLE #DATA(output).
Also you can combine this with substring to set the aufnr exact to 12 chars

SELECT FROM bseg JOIN aufk ON ( ltrim( aufk~aufnr, '0' ) = bseg~zuonr )
FIELDS bseg~hkont, bseg~zuonr, bseg~belnr, bseg~gjahr, aufk~prctr
WHERE bseg~hkont IN #s_hkont
INTO TABLE #DATA(output).
is also working

Related

SQL special group by on list of strings ending with *

I would like to perform a "special group by" on strings with SQL language, some ending with "*". I use postgresql.
I can not clearly formulate this problem, even if I have partially solved it, with select, union and nested queries which are not elegant.
For exemple :
1) INPUT : I have a list of strings :
thestrings
varchar(9)
--------------
1000
1000-0001
1000-0002
2000*
2000-0001
2000-0002
3000*
3000-00*
3000-0001
3000-0002
2) OUTPUT : That I would like my "special group by" return :
1000
1000-0001
1000-0002
2000*
3000*
Because 2000-0001 and 2000-0002 are include in 2000*,
and because 3000-00*, 3000-0001 and 3000-0002 are includes in 3000*
3) SQL query I do :
SELECT every strings ending with *
UNION
SELECT every string where the begining NOT IN (SELECT every string ending with *) <-- with multiple inelegant left functions and NOT IN subqueries
4) That what I'm doing return :
1000
1000-0001
1000-0002
2000*
3000*
3000-00* <-- the problem
The problem is : 3000-00* staying in my result.
So my question is :
How can I generalize my problem? to remove all string who have a same begining string in the list (ending with *) ?
I think of regular expressions, but how to pass a list from a select in a regex ?
Thanks for help.
Select only strings for which no master string exists in the table:
select str
from mytable
where not exists
(
select *
from mytable master
where master.str like '%*'
and master.str <> mytable.str
and rtrim(mytable.str, '*') like rtrim(master.str, '*') || '%'
);
Assuming that only one general pattern can match any given string, the following should do what you want:
select coalesce(tpat.thestring, t.thestring) as thestring
from t left join
t tpat
on t.thestring like replace(tpat.thestring, '*', '%') and
t.thestring <> tpat.thestring
group by coalesce(tpat.thestring, t.thestring);
However, that is not your case. However, you can adjust this with distinct on:
select distinct on (t.thestring) coalesce(tpat.thestring, t.thestring)
from t left join
t tpat
on t.thestring like replace(tpat.thestring, '*', '%') and
t.thestring <> tpat.thestring
order by t.thestring, length(tpat.thestring)

How to update a column for a set of rows?

The below query gives a set of rows with 3 columns.
Select
c.CaseID, i.ImageID, i.ImagePath
From
tblCase c WITH (NOLOCK)
inner join
tblName n WITH (NOLOCK) on c.CaseID = n.CaseID
inner join
tblImage i WITH (NOLOCK) on n.NameID = i.NameID
where
n.NameCode = '70'
The ImagePath column will have data like this with semi colon separated values.
ImageID=3215;FilePath=\2016\5\13\test.tif;ImageType=Original;PageNumber=1
The ImageType value needs to be changed to "duplicate" as below for all the rows returned from the query.
ImageID=3215;FilePath=\2016\5\13\test.tif;ImageType=duplicate;PageNumber=1
Any ideas? Is using a cursor good to do this kind of update? The number of rows will be a couple of thousands.
Thank you!
The best idea would be to stop storing multiple values in one column and normalize the database so that you don't run into issues like this.
Barring that, you can try to use REPLACE(), but you need to be very careful that you don't inadvertently change parts of the string that happen to match with your string.
REPLACE(ImagePath, ';ImageType=Original;', ';ImagetType=Duplicate;')
might work, but if that attribute can appear at the end of the string (without a trailing semicolon) then it might fail. It could also fail if there is a space in between the "=" and the attribute/value in some cases. It could also fail if it might be the first attribute without a leading semicolon. There might be some other possible failure cases as well - which is why this isn't how you should be storing your data.
Here is a try:
declare #s varchar(max) = 'ImageID=3215;FilePath=\2016\5\13\test.tif;ImageType=original;PageNumber=1'
select substring(#s, 0, charindex('imagetype=', #s)) + 'ImageType=duplicate' +
substring(#s, charindex(';', #s, charindex('imagetype=',#s)), len(#s))
http://rextester.com/edit/AVQO58898
Description: take everything till imagetype= and add ImageType=duplicate to it and add everything from first semicolon that occurs afterimagetype= till the end.
Use REPLACE
UPDATE i
SET i.ImagePath = REPLACE(i.ImagePath, ';ImageType=Original;', ';ImageType=duplicate;')
From tblCase c WITH (NOLOCK)
inner join tblName n WITH (NOLOCK) on c.CaseID = n.CaseID
inner join tblImage i WITH (NOLOCK) on n.NameID = i.NameID
where n.NameCode = '70'

Format sql column when using select

I have the following query to select record but i wan to format the column on the result set.
SELECT
COALESCE(dbo.tblMitchellLandscapeID.PatchSize,0) as PatchSize,
dbo.tblMitchellLandscape.MitchellLandscapeName
FROM tblMitchellLandscapeID
INNER JOIN dbo.tblMitchellLandscape
ON dbo.tblMitchellLandscapeID.MitchellLandscapeID=dbo.tblMitchellLandscape.MitchellLandscapeID
WHERE AssessmentVersionID = #AssessmentVersionID
"PatchSize" is a decimal value so it stored always like two decimals "15.10". All i trying to format to one decimal when the select statement is executed i wan to populate the result set like "15.1" rather than 15.10.
You can just cast it to the format you want:
SELECT CAST(COALESCE(li.PatchSize, 0) as decimal(5, 1)) as PatchSize,
l.MitchellLandscapeName
FROM tblMitchellLandscapeID li INNER JOIN
dbo.tblMitchellLandscape l
ON li.MitchellLandscapeID = l.MitchellLandscapeID
WHERE AssessmentVersionID = #AssessmentVersionID;
Notice the query is also easier to read (and write) if you use table aliases.

I need to remove leading zeros after a decimal point

this is my first time posting here and I am a basic SQL user and need help.
I have a varchar column that stores data like below:
Year.Docid
2007.000000001
2007.000000002
2007.000000003
2007.000000004
2007.000000005
2007.000000006
I need to join this data to another table that does not have all the zeros after the decimal, can someone please show me how to get the data to look like below:
Year Docid
2007.1
2007.2
2007.3
2007.4
2007.5
2007.6
I am using MICROSOFT SQL SERVER 2012
If the format is fixed, i.e. YYYY.NNNNNNNNN, you could just get the last 9 characters, convert them to int, convert the result back to varchar and concatenate back to the first 5 characters:
LEFT([Year.Docid], 5) + CAST(CAST(RIGHT([Year.Docid], 9) AS int) AS varchar(10))
However, it would make more sense to store Year and Docid as two separate int columns, in both tables. It is much easier to assemble them just for the output than do this processing every time and join on the results of it.
In SQL Server, assuming both columns are varchar, something like this should do you:
select *
from table_1 t1
join table_2 t2 on t2.docid = left(t2.docid,4)
+ '.'
+ convert(varchar,convert(int,right( t2.docid, len(t2.docid)-5 )))
You should bear in mind that making the one table's column an expression means that for that table/column, the query optimizer cannot use any indexes in the query plan.
This is a bit of work, but accomplishes the task of removing the zeros from the right of the dot:
SELECT SUBSTRING(YearDocid, 0, CHARINDEX('.', yearDocId)) +
REPLACE(SUBSTRING(yearDocId,
CHARINDEX('.', yearDocId),
LEN(yearDocID)),
'0', '')
FROM tab1;
sqlfiddle demo
To turn the long format into the short format:
SELECT LEFT('2007.000000001',5) + CAST(CAST(RIGHT('2007.000000001',LEN('2007.000000001')-5) AS int)AS VARCHAR)
...
To use that in a join:
SELECT
...
FROM
TABLE_1 T1
INNER JOIN TABLE_2 T2
ON LEFT(T1.pk,5) + CAST(CAST(RIGHT(T1.pk,LEN(T1.pk)-5) AS int)AS VARCHAR) = T2.pk
SELECT CONCAT(PARSENAME([Col_Varchar],2),'.',CONVERT(INT,PARSENAME([Col_Varchar],1))) FROM Tbl_sample

SQL Doesnt Want to match strings with spaces for some reason

I have this SQL Query that is not comparing properly so I commented it out the WHERE clause. When returning the AF.ActivityNote it always has 2 spaces after it no matter if I do RTRIM on it or not. I think those spaces are the issue that wont let the commented WHERE clause to properly match the string against userfield33.
SELECT CAST(UF.UserField33 AS NVARCHAR) , RTRIM(CAST(AF.ActivityNote AS NVARCHAR))
FROM [BCMTEST01].[dbo].[ActivityContacts] as AC INNER JOIN [BCMTEST01].[dbo].[ActivityFullView] as AF
ON AC.ActivityID = AF.ActivityID INNER JOIN [BCMTEST01].[dbo].[OpportunityExportView] as OP
ON AC.ContactID = OP.ContactServiceID INNER JOIN [BCMTEST01].[dbo].[UserFields] as UF
ON OP.ContactServiceID = UF.ContactServiceID
WHERE ContactID = 8376
--WHERE RTRIM(CAST(UF.UserField33 AS NVARCHAR) = RTRIM(CAST(AF.ActivityNote AS NVARCHAR))
ORDER BY ContactID ASC
First, you should always include the length when converting to nvarchar, varchar, char, and nchar. So use something like:
cast(uf.userfield33 as nvarchar(255)) -- or whatever length you like, so long as you have something
The last two characters are not spaces. Do something like:
select ascii(right( AF.ActivityNote, 1))
To see what the character value is. You can then use replace to get rid of it. Or, you can just chop off the last two characters (if that works for your application).
By the way, I am assuming you are using SQL Server based on the syntax of the query.
Here is an alternative where clause:
where (case when right(AF.ActivityNote, 2) = char(10)+CHar(13)
then LEFT(AF.ActivityNote, LEN(AF.ActivityNote) - 2)
else AF.ActivityNote
end) = CAST(UF.UserField33 AS NVARCHAR(255)
I'm not a big fan of case statements in where clauses. I would actually put the logic in a subquery. Also, I might have the order of the 10/13 backwards.