Convert EF core query in raw SQL - sql-server

Due to EF Core 3.x limitations, I need to convert a LINQ query in raw SQL.
The table looks like :
Id Name TagList
----------------------------
1 Line1 1;5;8
2 Line2 1;4
3 Line3 5
4 Line4 3;2;8
5 Line5
6 Line6 4
I need to get lines that matches a tag list provided has a parameter : let's call it tagSearch.
The EF query I've used with EF Core 2.x has Any() and Contains() method :
var result= _myRepository.Where(a => a.TagList.Any(t => tagSearch.Contains(t)))
if tagSearch is a List<string> that contains following items : 1 | 2
The result is :
Id Name TagList
----------------------------
1 Line1 1;5;8
2 Line2 1;4
4 Line4 3;2;8
I've tried several SQL queries with STRING_SPLIT and the closest is :
DECLARE #tagSearch NVARCHAR(400) = '1;2'
SELECT *
FROM MyTable
WHERE ( #tagSearch = SOME (SELECT value FROM STRING_SPLIT(TagList, ';'))
or TagList = SOME (SELECT value FROM STRING_SPLIT(#tagSearch, ';'))
)
But the result is not the one expected.

Related

Return Parts of an Array in Postgres

I have a column (text) in my Postgres DB (v.10) with a JSON format.
As far as i now it's has an array format.
Here is an fiddle example: Fiddle
If table1 = persons and change_type = create then i only want to return the name and firstname concatenated as one field and clear the rest of the text.
Output should be like this:
id table1 did execution_date change_type attr context_data
1 Persons 1 2021-01-01 Create Name [["+","name","Leon Bill"]]
1 Persons 2 2021-01-01 Update Firt_name [["+","cur_nr","12345"],["+","art_cd","1"],["+","name","Leon"],["+","versand_art",null],["+","email",null],["+","firstname","Bill"],["+","code_cd",null]]
1 Users 3 2021-01-01 Create Street [["+","cur_nr","12345"],["+","art_cd","1"],["+","name","Leon"],["+","versand_art",null],["+","email",null],["+","firstname","Bill"],["+","code_cd",null]]
Disassemble json array into SETOF using json_array_elements function, then assemble it back into structure you want.
select m.*
, case
when m.table1 = 'Persons' and m.change_type = 'Create'
then (
select '[["+","name",' || to_json(string_agg(a.value->>2,' ' order by a.value->>1 desc))::text || ']]'
from json_array_elements(m.context_data::json) a
where a.value->>1 in ('name','firstname')
)
else m.context_data
end as context_data
from mutations m
modified fiddle
(Note:
utilization of alphabetical ordering of names of required fields is little bit dirty, explicit order by case could improve readability
resulting json is assembled from string literals as much as possible since you didn't specified if "+" should be taken from any of original array elements
the to_json()::text is just for safety against injection
)

How to return just one result from SELECT CASE query?

i have a table like this
DBName p_server_fqdn p_server_alias q_server_fqdn q_server_alias
cube1 server1.com p1server.com server5.com q1server.com
cube1 server2.com p1server.com server6.com q1server.com
cube2 server3.com p2server.com server7.com q2server.com
cube2 server4.com p2server.com server8.com q2server.com
I want to run a case select query in which i get the alias of a server input that matches a server column with corresponding DBName
this is what im trying so far
$SAlias = Invoke-sqlcmd -Query "SELECT DISTINCT CASE
WHEN ($cubeTable.DBName like $CUBE_input) AND ($cubeTable.p_server_fqdn) like $server_input THEN p_server_alias
WHEN ($cubeTable.DBName like $CUBE_input) AND ($cubeTable.q_server_fqdn) like $server_input THEN q_server_alias
ELSE 'unknown'
END as SAlias
FROM table $cubeTable" -ConnectionString "connectionstuff" | Select -ExpandProperty SAlias
but when i try the query itself in SSMS (with hardcoded values like cube1 and server2.com), i get back 2 rows with the row that dont match the DBName as "unknown" while 1 row shows p_server_alias
result im getting:
i should only get back the 1st row: p1server.com in this case, so why am i also getting unknown?
set #cubeInput = 'cube1';
set #serverInput = 'server6.com';
select
case when count(*) = 0 then 'UNKNOWN'
when m.p_server_fqdn = #serverInput then m.p_server_alias
when m.q_server_fqdn = #serverInput then m.q_server_alias
end as alias
from mytable m
where DBName = #cubeInput and (
p_server_fqdn = #serverInput
or q_server_fqdn = #serverInput
);
here is the implementation of my answer : http://sqlfiddle.com/#!9/b967a22/61
#Cataster solution return 2 rows becouse actualy he get 4 rows (3 rows 'unkown' and 1 row 'p1server.com') then he put distinct in the query. it's make result become 2 rows.
my solution little bit tricky :). Using filter in the query. than if we get no row as the result use the count function. So we get 1 row and the value is 0 than show it as 'UNKNOWN'.

Adding multiple records from a string

I have a string of email addresses. For example, "a#a.com; b#a.com; c#a.com"
My database is:
record | flag1 | flag2 | emailaddresss
--------------------------------------------------------
1 | 0 | 0 | a#a.com
2 | 0 | 0 | b#a.com
3 | 0 | 0 | c#a.com
What I need to do is parse the string, and if the address is not in the database, add it.
Then, return a string of just the record numbers that correspond to the email addresses.
So, if the call is made with "A#a.com; c#a.com; d#a.com", the rountine would add "d#a.com", then return "1, 3,4" corresponding to the records that match the email addresses.
What I am doing now is calling the database once per email address to look it up and confirm it exists (adding if it doesn't exist), then looping thru them again to get the addresses 1 by 1 from my powershell app to collect the record numbers.
There has to be a way to just pass all of the addresses to SQL at the same time, right?
I have it working in powershell.. but slowly..
I'd love a response from SQL as shown above of just the record number for each email address in a single response. That is, "1,2,4" etc.
My powershell code is:
$EmailList2 = $EmailList.split(";")
# lets get the ID # for each eamil address.
foreach($x in $EmailList2)
{
$data = exec-query "select Record from emailaddresses where emailAddress = #email" -parameter #{email=$x.trim()} -conn $connection
if ($($data.Tables.record) -gt 0)
{
$ResponseNumbers = $ResponseNumbers + "$($data.Tables.record), "
}
}
$ResponseNumbers = $($ResponseNumbers+"XX").replace(", XX","")
return $ResponseNumbers
You'd have to do this in 2 steps. Firstly INSERT the new values and then use a SELECT to get the values back. This answer uses delimitedsplit8k (not delimitedsplit8k_LEAD) as you're still using SQL Server 2008. On the note of 2008 I strongly suggest looking at upgrade paths soon as you have about 6 weeks of support left.
You can use the function to split the values and then INSERT/SELECT appropriately:
DECLARE #Emails varchar(8000) = 'a#a.com;b#a.com;c#a.com';
WITH Emails AS(
SELECT DS.Item AS Email
FROM dbo.DelimitedSplit8K(#Emails,';') DS)
INSERT INTO YT (emailaddress) --I don't know what the other columns value should be, so have excluded
SELECT E.Email
FROM dbo.YourTable YT
LEFT JOIN Emails E ON YT.emailaddress = E.Email
WHERE E.Email IS NULL;
SELECT YT.record
FROM dbo.YourTable YT
JOIN dbo.DelimitedSplit8K(#Emails,';') DS ON DS.Item = YT.emailaddress;

Add incremental number in duplicate records

I have SSIS package, which retrieves all records including duplicates. My question is how to add an incremental value for the duplicate records (only the ID and PropertyID).
Eg
Records from a Merge Join
ID Name PropertyID Value
1 A 1 123
1 A 1 223
2 B 2 334
3 C 1 22
3 C 1 45
Now I need to append an incremental value at the end of the each record as
ID Name PropertyID Value RID
1 A 1 123 1
1 A 1 223 2
2 B 2 334 1
3 C 1 22 1
3 C 1 45 2
Since ID 1 & 3 are returned twice, the first record has RID as 1 and the second record as 2.
ID and PropertyID need to be considered to generate the Repeating ID i.e RID.
How can I do it in SSIS or using SQL command?
Update #1:
Please correct me if I'm wrong, since the data is not stored in any table yet, I'm unable to use the select query using rownumber(). Any way I can do it from the Merge Join?
You could use ROW_NUMBER:
SELECT ID,
Name,
PropertyID,
Value,
ROW_NUMBER() OVER(PARTITION BY ID, PropertyID ORDER BY Value) As RID
FROM TableName
This will do the job for you: https://paultebraak.wordpress.com/2013/02/25/rank-partitioning-in-etl-using-ssis/
You will need to write a custom script, something like this:
public
class
ScriptMain : UserComponent
{
string _sub_category = “”;
int _row_rank = 1;
public override void Input0_ProcessInputRow(Input0Buffer Row)
{
if (Row.subcategory != _sub_category)
{
_row_rank = 1;
Row.rowrank = _row_rank;
_sub_category = Row.subcategory;
}
else
{
_row_rank++;
Row.rowrank = _row_rank;
}
}
}

Hive query, better option to self join

So I am working with a hive table that is set up as so:
id (Int), mapper (String), mapperId (Int)
Basically a single Id can have multiple mapperIds, one per mapper such as an example below:
ID (1) mapper(MAP1) mapperId(123)
ID (1) mapper(MAP2) mapperId(1234)
ID (1) mapper(MAP3) mapperId(12345)
ID (2) mapper(MAP2) mapperId(10)
ID (2) mapper(MAP3) mapperId(12)
I want to return the list of mapperIds associated to each unique ID. So for the above example I would want the below returned as a single row.
1, 123, 1234, 12345
2, null, 10, 12
The mapper Strings are known, so I was thinking of doing a self join for every mapper string I am interested in, but I was wondering if there was a more optimal solution?
If the assumption that the mapper column is distinct with respect to a given ID is correct, you could collect the mapper column and the mapperid column to a Map using brickhouse collect. You can clone the repo from that link and build the jar with Maven.
Query:
add jar /complete/path/to/jar/brickhouse-0.7.0-SNAPSHOT.jar;
create temporary function collect as 'brickhouse.udf.collect.CollectUDAF';
select id
,id_map['MAP1'] as mapper1
,id_map['MAP2'] as mapper2
,id_map['MAP3'] as mapper3
from (
select id
,collect(mapper, mapperid) as id_map
from some_table
group by id
) x
Output:
| id | mapper1 | mapper2 | mapper3 |
------------------------------------
1 123 1234 12345
2 10 12

Resources