Like Predicate in T-SQL - sql

Retrieve the product number, name, and list price of products whose product number begins 'BK-' followed by any character other than 'R’, and ends with a '-' followed by any two numerals. Question belongs to Lab file i'm working on. Below is what i'v tried:
Select p.ProductNumber, p.Name,p.ListPrice,p.ProductNumber
From SalesLT.Product as p
Where p.ProductNumber Like 'BK-%[^r]%-[0-9][0-9]'
Column Name
FR-R32B-78
FR-R32R-78
HL-U703-R
HL-U703
SO-B303-M
SO-B303-L
HL-U703-B
CA-1038
LJ-0132-S
LJ-0132-M
BK-M82S-32
BK-M82S-33
BK-M82S-38
BK-R33R-62
BK-R33R-44

The problem is you have % before [^r]
Select p.ProductNumber, p.Name,p.ListPrice,p.ProductNumber
From SalesLT.Product as p
Where p.ProductNumber Like 'BK-[^r]%-[0-9][0-9]'
This should work fine i think.
The reason is %[^r]% means - Any symbols followed by not r followed by any symbols. Which is true for any of them.
Example R33R -> R is any symbols , 3 is not r and 3R is any symbols.

declare #t table (ProductNumber varchar(100));
insert into #t
values
('FR-R32B-78'),
('FR-R32R-78'),
('HL-U703-R'),
('HL-U703'),
('SO-B303-M'),
('SO-B303-L'),
('HL-U703-B'),
('CA-1038'),
('LJ-0132-S'),
('LJ-0132-M'),
('BK-M82S-32'),
('BK-M82S-33'),
('BK-M82S-38'),
('BK-R33R-62'),
('BK-R33R-44')
Select *
From #t
Where ProductNumber Like 'BK-%-[0-9][0-9]' and ProductNumber not like '___R%';

Related

mismatched input 'from'. Expecting: ',', <expression>

I have a query that I am running on AWS athena that should return all the filenames that are not contained in the second table. I am basically trying to find all the filename that are not in ejpos landing table.
The one table looks like this (item sales):
origin_file
run_id
/datarite/ejpos/8023/20220706/filename1
8035
/datarite/ejpos/8023/20220706/filename2
8035
/datarite/ejpos/8023/20220706/filename3
8035
The other table looks like this (ejpos_files_landing):
filename
filename1
filename2
filename3
filename4
They don't have the same number of rows, hence I am trying to find the file names that are in ejpos_pos_landing but not in item sales table.
I get this error when I run:
mismatched input 'from'. Expecting: ',', <expression>
The query is here:
SELECT trim("/datarite/ejpos/8023/20220706/" from "validated"."datarite_ejpos_itemsale" where
run_id = '8035') as origin_file,
FROM "validated"."datarite_ejpos_itemsale"
LEFT JOIN "landing"."ejpos_landing_files" ON "landing"."ejpos_landing_files".filename =
"validated"."datarite_ejpos_itemsale".origin_file
WHERE "landing"."ejpos_landing_files".filename IS NULL;
The expected result would be:
|filename4|
Because it is not in the other table
Can anyone assist?
There is a lot of wrong stuff in your query based on the example data and declared goals.
trim("/datarite/ejpos/8023/20220706/" from "validated"."datarite_ejpos_itemsale" where run_id = '8035') as origin_file is not a valid sql.
ON "landing"."ejpos_landing_files".filename = "validated"."datarite_ejpos_itemsale".origin_file will not work cause origin_file is prefixed. You can use strpos if there should be only one instance of filename in the origin_file.
your join and filtering condition are build to find items present in datarite_ejpos_itemsale and missing in ejpos_landing_files while you state the vise versa is needed.
the mentioned in the comments extra comma
Try next:
-- sample data
WITH item_sales(origin_file, run_id) AS (
VALUES ('/datarite/ejpos/8023/20220706/filename1', 8035),
('/datarite/ejpos/8023/20220706/filename2', 8035),
('/datarite/ejpos/8023/20220706/filename3', 8035),
('/datarite/ejpos/8023/20220706/filename4', 8036)
),
ejpos_files_landing(filename) as(
VALUES ('filename1'),
('filename2'),
('filename3'),
('filename4')
)
-- query
select filename
from ejpos_files_landing l
left outer join item_sales s -- reverse the join
on strpos(s.origin_file, l.filename) >= 1 -- assuming that filename should be present only one time in the string
and s.run_id = 8035 -- if you need to filter out run id
where s.origin_file is null
Output:
filename
filename4
Alternative approach you can try:
-- query
select filename
from ejpos_files_landing l
where filename not in (
select element_at(split(origin_file, '/'), -1) -- split by '/' and get last
from item_sales
where run_id = 8035
)

Validating Phone Numbers in Batch with PostgreSQL

This is my SQL:
SELECT
countries.locl_ctry_id,
countries.icc,
countries.active,
networks.locl_ntwrk_id,
networks.locl_ctry_id,
numberings.locl_ntwrk_id,
numberings.ndc,
numberings.size
FROM countries
LEFT JOIN networks
ON networks.locl_ctry_id = countries.locl_ctry_id
LEFT JOIN numberings
ON numberings.locl_ntwrk_id = networks.locl_ntwrk_id
WHERE
countries.active = 'true'
AND numberings.locl_ntwrk_id NOTNULL
AND CONCAT(countries.icc, numberings.ndc)
LIKE LEFT('381645554330', CHAR_LENGTH(CONCAT(countries.icc, numberings.ndc)))
AND LENGTH('381645554330') = numberings.size
I would like to run this script for a batch of numbers, for example:
381645554330 ‭
381629000814‬‬
381644446555‬
‭38975300155‬
‭38975604099 ‭
38976330923‬‬ ‭
38977772090‬ ‭
38978250177‬ ‭
38970333730‬
‭38971388262‬
‭38972228855‬
Take a look at the database structure here: http://sqlfiddle.com/#!17/13ce29/27
It needs to validate the Prefix as well as the Length of the number.
Any suggestions how to achieve this?
Put the batch of numbers in a union all subquery.
SELECT
countries.locl_ctry_id,
countries.icc,
countries.active,
networks.locl_ntwrk_id,
networks.locl_ctry_id,
numberings.locl_ntwrk_id,
numberings.ndc,
numberings.size
FROM countries
LEFT JOIN networks
ON networks.locl_ctry_id = countries.locl_ctry_id
LEFT JOIN numberings
ON numberings.locl_ntwrk_id = networks.locl_ntwrk_id
JOIN ( select '381645554330' as num
union all
select '38976330923‬‬‬‬'
union all
select '38975300155‬‬‬' ) batch_numbers
ON CONCAT(countries.icc, numberings.ndc)
LIKE LEFT(batch_numbers.num, CHAR_LENGTH(CONCAT(countries.icc, numberings.ndc)))
AND LENGTH(batch_numbers.num) = numberings.size
WHERE
countries.active = 'true'
AND numberings.locl_ntwrk_id NOTNULL
It seems the objective is not ability to return the set of values currently returned by the single, but to make an evaluation of the of multiple values. The issue with the above it requires an a-priori knowledge of and a modification to the query for each set to evaluate. The follow will attempt to remove that requirement.
Let's begin by developing a base line query as an extension to Jakup's "union" solution.
--- create a baseline solution
with to_be_validated (test_num) as -- CTE used strictly as data generator fir query
( values ('381645554330')
, ('381629000814')
, ('381644446555')
, ('38975300155')
, ('38975604099')
, ('38976330923')
, ('38977772090')
, ('38978250177')
, ('38970333730')
, ('38971388262')
, ('38972228855')
, ('81771388262')
, ('55572228855')
)
--- base query
select test_num
, case when icc is not null then 'Valid' else 'Invalid' end validation
from to_be_validated
left join(
select countries.icc, numberings.ndc, numberings.size
from countries
join networks on networks.locl_ctry_id = countries.locl_ctry_id
join numberings on numberings.locl_ntwrk_id = networks.locl_ntwrk_id
) base on ( concat(base.icc, base.ndc) = left( test_num, char_length(concat(base.icc, base.ndc)))
and length(test_num) = base.size
)
;
Notes on Query and Modifications:
1. the column countries.active is defined as binary, thus already providing a True/False value. Thus checking for "= 'true' is unnecessary. Altered to just contries.active.
2. The column numberings.locl_ntwrk_id is restricted to being NOT NULL, so the Predicate "nullnumberings.locl_ntwrk_id NOTNULL" is always true. Removed predicate.
3. The LEFT JOIN on networks and numberings will generate a result set with all countries, all networks, all numberings, even when the combination is itself invalid. This results in validating each phone number against every combination of the 3 base tables. Alter these inner joins.
4. Finally, I added a couple extra numbers to your test data. These are intended to fail the desired validation. You should always test with considerable invalid data, otherwise you cannot know if procedure/query/whatever gracefully and properly handles it.
Now with a base query in hand it's possible to just end here. But to be generally useful you cannot edit the query each time it wanted. Therefore lets wrap a function definition around it. We'll do this by wrapping a function definition around that base query, and provide either an array or a delimited string containing the phone numbers to b evaluated.
In each the base query remains the same, and we keep the CTE, but the CTE is modified to build a row for each phone number provided.
-- SQL Function with and Array input
create or replace function validate_phone_numbers( phone_numbers text[])
returns table ( phone_number text
, validation_status text
)
language sql
as $$
with to_be_validated as
( select unnest (phone_numbers) test_num )
-- Insert base query here --
$$
-- Test with Array
select phone_number, validation_status
from validate_phone_numbers (ARRAY
[ ('381629000814')
, ('381644446555')
, ('38975300155')
, ('38975604099')
, ('38976330923')
, ('38977772090')
, ('38978250177')
, ('38970333730')
, ('38971388262')
, ('38972228855')
, ('81771388262')
, ('55572228855')
]
) ;
With a minor extension we a delimited string version.
create or replace function validate_phone_numbers_with_string( phone_numbers text, delimiter text default ',')
returns table ( phone_number text
, validation_status text
)
language sql
as $$
with to_be_validated as
( select unnest (string_to_array (phone_numbers, delimiter)) test_num)
-- Insert base query here --
$$ ;
-- test with string
select phone_number, validation_status
from validate_phone_numbers_with_string('381629000814,381644446555,38975300155,38975604099,38976330923,38977772090,38978250177,38970333730,38971388262,38972228855,81771388262,55572228855');

Update UDF names stored in table to add parameter value

I have thousands of UDF names stored in table and executed dynamically where it is required. The problem is I have added one new parameter unit to the function dbo.GetStockPrice(6544,1) so I need to send one more parameter value for now 1 bue it can be any and the data should be changed to dbo.GetStockPrice(6544,1,1) for all the rows where dbo.GetStockPrice is exist. So I am seeking for the query to update these all at once.
Sample Data
DECLARE #table AS TABLE(id INT, UDF VARCHAR(1000))
INSERT INTO #table VALUES
(7774,'dbo.GetStockPrice(1211,1)*dbo.GetStockPrice(1211,1)'),
(7775,'dbo.GetStockPrice(232,1)'),
(7778,'dbo.GetStockPrice(6456,1)'),
(7780,'dbo.GetStockPrice(34,1)'),
(7784,'dbo.FNACondition(dbo.FNAMargin(1,NULL,0), 0, dbo.GetStockPrice(654,1)+1)'),
(7786,'dbo.GetStockPrice(9876,1)'),
(7906,'dbo.GetStockPrice(5565,1)'),
(7911,'dbo.GetStockPrice(7886,1)'),
(7912,'dbo.GetStockPrice(87,1)'),
(8403,'dbo.PriceValue(479,NULL,NULL)*dbo.GetStockPrice(6544,1)+dbo.FNAMargin(1,NULL,0)')
Expected Output:
7774 dbo.GetStockPrice(1211,1,1)*dbo.GetStockPrice(1211,1,1)
7775 dbo.GetStockPrice(232,1,1)
so on......
I am still trying with REPLACE, SUBSTRING but unable to come out with any solution. Getting difficulties with it's different length and position in the row.
Seeking Help !! Thank you in Advance :)
Try it with this approach:
DECLARE #table AS TABLE(id INT, UDF VARCHAR(1000))
INSERT INTO #table VALUES
(7774,'dbo.GetStockPrice(1211,1)*dbo.GetStockPrice(1211,1)'),
(7775,'dbo.GetStockPrice(232,1)'),
(7778,'dbo.GetStockPrice(6456,1)'),
(7780,'dbo.GetStockPrice(34,1)'),
(7784,'dbo.FNACondition(dbo.FNAMargin(1,NULL,0), 0, dbo.GetStockPrice(654,1)+1)'),
(7786,'dbo.GetStockPrice(9876,1)'),
(7906,'dbo.GetStockPrice(5565,1)'),
(7911,'dbo.GetStockPrice(7886,1)'),
(7912,'dbo.GetStockPrice(87,1)'),
(7913,'dbo.Blah(87,1)'),
(8403,'dbo.PriceValue(479,NULL,NULL)*dbo.GetStockPrice(6544,1)+dbo.FNAMargin(1,NULL,0)');
--The query
WITH SplitToParts AS
(
SELECT t.*
,A.parted
,ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS PartNr
,B.part.value('text()[1]','nvarchar(max)') AS Part
FROM #table AS t
CROSS APPLY(SELECT CAST('<x>' + REPLACE((SELECT t.UDF AS [*] FOR XML PATH('')),'dbo.GetStockPrice(','</x><x>$$$FoundIt$$$</x><x>') + '</x>' AS XML)) AS A(parted)
CROSS APPLY parted.nodes(N'/x') AS B(part)
WHERE UDF LIKE '%dbo.GetStockPrice(%'
)
,modified AS
(
SELECT *
,CASE WHEN LAG(stp.Part) OVER(PARTITION BY id ORDER BY PartNr)='$$$FoundIt$$$' THEN STUFF(stp.Part,CHARINDEX(')',stp.Part),0,',1') ELSE stp.Part END AS Added
FROM SplitToParts AS stp
)
SELECT t2.*
,(
SELECT REPLACE(m.added,'$$$FoundIt$$$','dbo.GetStockPrice(')
FROM modified AS m
WHERE m.id=t2.id
ORDER BY m.PartNr
FOR XML PATH(''),TYPE
).value('.','nvarchar(max)')
FROM #table AS t2
WHERE UDF LIKE '%dbo.GetStockPrice(%';
The result
7774 dbo.GetStockPrice(1211,1,1)*dbo.GetStockPrice(1211,1,1)
7775 dbo.GetStockPrice(232,1,1)
7778 dbo.GetStockPrice(6456,1,1)
7780 dbo.GetStockPrice(34,1,1)
7784 dbo.FNACondition(dbo.FNAMargin(1,NULL,0), 0, dbo.GetStockPrice(654,1,1)+1)
7786 dbo.GetStockPrice(9876,1,1)
7906 dbo.GetStockPrice(5565,1,1)
7911 dbo.GetStockPrice(7886,1,1)
7912 dbo.GetStockPrice(87,1,1)
8403 dbo.PriceValue(479,NULL,NULL)*dbo.GetStockPrice(6544,1,1)+dbo.FNAMargin(1,NULL,0)
Some explanation: The string will be cut in parts using your function's name as splitter. Gladfully you tagged this with [sql-server-2012] so you can use LAG(). This will test the previous element, if it is $$$FoundIt$$$. In this case the first closing bracket will get an additional ,1. The rest is reconcatenation.
Attention: If your call might include a computed value such as
dbo.GetStockPrice(1211,(1+2))
or
dbo.GetStockPrice(dbo.SomeOtherFunc(1),1)
...the first closing bracket is the wrong place to insert the ,1. But this would get really tricky... You'd have to run through it, char by char, and count the opening brackets to find the related closing one.

SQL Server: Conversion failed when converting the varchar value '1,2'

I have a query like this
select
t.tiid, t.employeeid, t.remarks,
dd.DocID, dd.Document, dd.DocuName
from
ti t
inner join
History cth on cth.tiid = t.tiid
inner join
Downloads dd on dd.DocID = cth.DocID
My data in table is like this
History:
DocID DocuName
1,2 abc.dox,def.docx
Downloads
DocID DocuName document
1 abc.docx x3400000efg..
2 def.docx xc445560000...
but when I execute this query, it shows an error:
Conversion failed when converting the varchar value '1,2' to data type int.
The DocID of history is multiple DocID had been combined with comma, So you can not compare the value directly( One value vs Multiple values).
You can check whether the multiple values contain the specify value use CHARINDEX.
To make sure complete matched of sub string,need a delimiter to indicate a single value, otherwise can get wrong result.
For Eample:
CHARINDEX('1,','12,2,3') will be 1, but in fact, there is no 1 in the string.
select
t.tiid,
t.employeeid,
t.remarks,
dd.DocID,
dd.Document,
dd.DocuName
from ti t
inner join History cth on cth.tiid=t.tiid
inner join Downloads dd on CHARINDEX(','+LTRIM(dd.DocID)+',',','+cth.DocID+',')>0
As the error says, you are trying to equate a string with int.You need to convert the int DocID as string and check if it's present in the comma-separated DocID .Something like
SELECT t.tiid,
t.employeeid,
t.remarks,
dd.DocID,
dd.Document,
dd.DocuName
FROM ti t
INNER JOIN History cth ON cth.tiid=t.tiid
INNER JOIN Downloads dd ON CHARINDEX(',' + CAST(dd.DocID AS VARCHAR(10)) + ',',',' + cth.DocID + ',')>0

Postgresql : How to update one field for all duplicate values based at the end of the string of a field except one row

http://sqlfiddle.com/#!9/b98ea/1 (Sample Table)
I have a table with the following fields:
transfer_id
src_path
DH_USER_ID
email
status_state
ip_address
src_path field contains a couple of duplicates filename values but a different folder name at the beginning of the string.
Example:
191915/NequeVestibulumEget.mp3
/191918/NequeVestibulumEget.mp3
191920/NequeVestibulumEget.mp3
I am trying to do the following:
Set status_state field to 'canceled' for all the duplicate filenames within (src_path) field except for one.
I want the results to look like this:
http://sqlfiddle.com/#!9/5e65f/2
*I apologize in advance for being a complete noob, but I am taking SQL at college and I need help.
SQL Fiddle Demo
fix_os_name: Fix the windows path string to unix format.
file_name: Split the path using /, and use char_length to bring last split.
drank: Create a seq for each filename. So unique filename only have 1, but dup also have 2,3 ...
UPDATE: check if that row have rn > 1 mean is a dup.
.
Take note the color highlight is wrong, but code runs ok.
with fix_os_name as (
SELECT transfer_id, replace(src_path,'\','/') src_path,
DH_USER_ID, email, status_state, ip_address
FROM priority_transfer p
),
file_name as (
SELECT
fon.*,
split_part(src_path,
'/',
char_length(src_path) - char_length(replace(src_path,'/','')) + 1
) sfile
FROM fix_os_name fon
),
drank as (
SELECT
f.*,
row_number() over (partition by sfile order by sfile) rn
from file_name f
)
UPDATE priority_transfer p
SET status_state = 'canceled'
WHERE EXISTS ( SELECT *
FROM drank d
WHERE d.transfer_id = p.transfer_id
AND d.rn > 1);
ADD: One row is untouch
Use the regexp_matches function to separate the file name from the directory.
From there you can use distinct() to build a table with unique values for the filename.
select
regexp_matches(src_path, '[a-zA-Z.0-9]*$') , *
from priority_transfer
;