How to Query Data with Specified Multiple Field Values? - concatenation

I have a table as follows:
Id = stretch(1..100,1000)
area = take(`A`B`C`D`E`F`G`H`I`J,1000)
qyt = rand(100.00,1000)
t = table(Id,area,qyt)
I want to query data with multiple field values.
Query condition:
field value “Id=1“, “area“ = A, F, G;
field value “Id=2“, “area“ = B, C, D;
field value “Id=3“, “area“ = B, C, G;
I tried the following method, querying each record with a where clause.
select * from t where (Id =1 and area = `A) or (Id = 1 and area = `F) or(Id = 1 and area = `G)
The code is simple but long. Is there any easier way to solve this problem?

The query condition involves field “Id“ and “area“. First, you can add a new field “newCol“ that combines these two fields.
temp = select *,string(Id)+area as newCol from t
Then, conduct a query as follows:
aim_row = `1A`1F`1G`2B`2C`2D`3B`3C`3G
result = select Id,area, qyt from temp where newCol in aim_row
Output:
Id area qyt
-- ---- ------------------
1 A 30.710145598277449
1 F 37.276206677779555
1 G 81.456008832901716
2 B 47.396290418691933
2 C 68.868489493615925
2 D 72.536952490918338
3 B 77.235422702506184
3 C 32.31446212157607
3 G 39.283064194023609

Related

Output of a column to only have two decimal numbers?

I'm showing the query output on a default ViewGrid on a VB.NET web application and some of the output values give me 4 decimal values while I only need two decimal values do to the result for showing a currency.
How can I specify in the query to only show me a maximum of two decimal values for the values of D.ORIG_PRC and D.DISC_AMT?
My Query
SELECT H.Emp_ID, H.Cust_ID, H.Rgst_ID, D.TRAN_LN_NUM, D.DISC_CD, D.AUTH_EMP_ID, D.ORIG_PRC, D.DISC_AMT, D.DISC_PCT, D.GL_ACCT_ID
FROM Transaction_Header H
INNER Join LN_Detail L ON (H.Str_ID = L.Str_ID And H.Rgst_ID = L.Rgst_ID And H.Tran_ID = L.Tran_ID)
INNER Join LN_Discount D ON (L.Str_ID = D.Str_ID And L.Rgst_ID = D.Rgst_ID And L.Tran_ID = D.Tran_ID And L.Tran_LN_Num = D.Tran_LN_Num)
WHERE(H.Str_ID = #Str_ID)
And (H.Tran_ID = #Tran_ID)
And ((H.Rgst_ID = #Rgst_ID) Or (#Rgst_ID Is NULL Or #Rgst_ID = ''))

Update after Insert not working sometimes

I have procedure that inserts data into a table A and then updates another table B.
After passing values to the procedure, insert seems to be working fine, but update doesn't work sometimes.
INSERT INTO A (a, b, c) VALUES (#v_a, #v_b, #v_c)
...
UPDATE B SET status = '02' WHERE a = #v_a, b = #v_b
#v_a, #v_b, #v_c are values that procedure gets from my code.
The code looks similar as above. When I check table A, it inserts correct data, and B it has data that's true WHERE a = #v_a, b = #v_b.
But sometimes UPDATE doesn't work.
Is my code just wrong? or did anyone have the same problem?
Edit :
I was just sketching out so made a mistake. The code is
UPDATE B SET status = '02' WHERE a = #v_a AND b = #v_b So there is no syntax error. I guess I'll need to parse it through once again.
Thank you for all the replies though.
Change your comma separating the variables to AND:
UPDATE B SET status = '02' WHERE a = #v_a AND b = #v_b;
Or OR:
UPDATE B SET status = '02' WHERE a = #v_a OR b = #v_b;

Comparison of multiselect picklist with a field in text format in apex

I have an object with number of records in this format with Name in Text format -
Id Name
1 A,B,C
2 A,B
3 A
4 B
5 A,C
6 A,D
I have a multi-select picklist with values as:
A
B
C
D
So if I select B and C in my picklist, then I must have the records from the table in which name consists of B or C or (B and C) i.e. in this case, it should show 4 records:
1 A,B,C
2 A,B
4 B
5 A,C
I am using SQL query with IN and INCLUDES keyword but I am unable to achieve this functionality.
This depends on how many options you have for using soql. One way I can see it is:
Object__c myObject = new Object__c();
object.Name = 'A,B,D';
object.Multi_Select_Name__c = 'A;E';
insert object;
String query = 'select Id from Object__c';
//now we want to do a multi picklist, which is a String separated by ';'
List<String> nameSelections = object.Multi_Select_Name__c.split(';');
if(nameSelections.size() > 0) {
query += ' where ';
for(Integer i = 0; i < nameSelections.size(); i++) {
nameSelections[i] = 'Name like \'%' + nameSelections[i] + '%\'';
}
query += String.join(nameSelections, ' or ');
}
List<Object__c> objects = (List<Object__c)database.query(query);
This will create a query like:
'select Id from Object__c where Name like '%A%' or Name like '%E%'
Selecting all Object__c's where Name contains either A or E, generated from your multiselect.
Syntax errors may apply, I just wrote this real quick :) Ill double check myself.
EDIT:
This code works to build the query
String query = 'select Id from Object__c';
String multiSelect = 'A;E';
List<String> nameSelections = multiSelect.split(';');
if(nameSelections.size() > 0 ){
query += ' where ';
for(Integer i = 0; i < nameSelections.size(); i++) {
nameSelections[i] = 'Name like \'%' + nameSelections[i] + '%\'';
}
query += String.join(nameSelections, ' or ');
}
system.debug(LoggingLevel.INFO, query);

Cross checking query on the same table

How do I write a query to display records where sample1_id = 3 and sample2_id = 5 or Sample1_id = 5 and sample2_id =3.
Meaning it should check the row of sample1_id and see wherever there is a record of 5 in line with sample2_id having a record of 3 and also checked if sample1_id is having a record of 5 line with sample2_id having a record of 3.
I hope my question do make sense
Just going by what you have provided, a mock statement would look like this:
SELECT *
FROM MyTable
WHERE (sample1_id = 3 AND sample2_id = 5)
OR (sample1_id = 5 AND sample2_id = 3);
If this is not correct, please provide some sample data and a sample of the results you would like.
Added the following in response to question about using variables:
DECLARE #intId1 int,
#intId2 int;
SET #intId1 = 3;
SET #intId2 = 5;
BEGIN;
SELECT *
FROM MyTable
WHERE (sample1_id = #intId1 AND sample2_id = #intId2)
OR (sample1_id = #intId2 AND sample2_id = #intId1);
END;

Convert SQL Server varbinary(max) into a set of primary keys of type int

Disclaimer: not my code, not my database design!
I have a column of censusblocks(varbinary(max), null) in a MS SQL Server 2008 db table (call it foo for simplicity).
This column is actually a null or 1 to n long list of int. The ints are actually foreign keys to another table (call it censusblock with a pk id of type of int), numbering from 1 to ~9600000.
I want to query to extract the censusblocks list from foo, and use the extracted list of int from each row to look up the corresponding censusblock row. There's a long, boring rest of the query that will be used from there, but it needs to start with the census blocks pulled from the foo table's censusblocks column.
This conversion-and-look-up is currently handled on the middle tier, with a small .NET utility class to convert from List<int> to byte[] (and vice versa), which is then written into/read from the db as varbinary. I would like to do the same thing, purely in SQL.
The desired query would go something along the lines of
SELECT f.id, c.id
FROM foo f
LEFT OUTER JOIN censusblock c ON
c.id IN f.censusblocks --this is where the magic happens
where f.id in (1,2)
Which would result in:
f.id | c.id
1 8437314
1 8438819
1 8439744
1 8441795
1 8442741
1 8444984
1 8445568
1 8445641
1 8447953
2 5860657
2 5866881
2 5866881
2 5866858
2 5862557
2 5870475
2 5868983
2 5865207
2 5863465
2 5867301
2 5864057
2 5862256
NB: the 7-digit results are coincidental. The range is, as stated above, 1-7 digits.
The actual censusblocks column looks like
SELECT TOP 2 censusblocks FROM foo
which results in
censublocks
0x80BE4280C42380C7C080CFC380D37580DC3880DE8080DEC980E7D1
0x596D3159858159856A59749D59938B598DB7597EF7597829598725597A79597370
For further clarification, here's the guts of the .NET utility classes conversion methods:
public static List<int> getIntegersFromBytes(byte[] data)
{
List<int> values = new List<int>();
if (data != null && data.Length > 2)
{
long ids = data.Length / 3;
byte[] oneId = new byte[4];
oneId[0] = 0;
for (long i = 0; i < ids; i++)
{
oneId[0] = 0;
Array.Copy(data, i * 3, oneId, 1, 3);
if (BitConverter.IsLittleEndian)
{ Array.Reverse(oneId); }
values.Add(BitConverter.ToInt32(oneId, 0));
}}
return values;
}
public static byte[] getBytesFromIntegers(List<int> values)
{
byte[] data = null;
if (values != null && values.Count > 0)
{
data = new byte[values.Count * 3];
int count = 0;
byte[] idBytes = null;
foreach (int id in values)
{
idBytes = BitConverter.GetBytes(id);
if (BitConverter.IsLittleEndian)
{ Array.Reverse(idBytes); }
Array.Copy(idBytes, 1, data, count * 3, 3);
count++;
} }
return data;
}
An example of how this might be done. It is unlikely to scale brilliantly.
If you have a numbers table in your database it should be used in place of nums_cte.
This works by converting the binary value to a literal hex string, then reading it in 8-character chunks
-- create test data
DECLARE #foo TABLE
(id int ,
censusblocks varbinary(max)
)
DECLARE #censusblock TABLE
(id int)
INSERT #censusblock (id)
VALUES(1),(2),(1003),(5030),(5031),(2),(6)
INSERT #foo (id,censusblocks)
VALUES (1,0x0000000100000002000003EB),
(2,0x000013A6000013A7)
--query
DECLARE #biMaxLen bigint
SELECT #biMaxLen = MAX(LEN(CONVERT(varchar(max),censusblocks,2))) FROM #foo
;with nums_cte
AS
(
SELECT TOP (#biMaxLen) ((ROW_NUMBER() OVER (ORDER BY a.type) - 1) * 8) AS n
FROM master..spt_values as a
CROSS JOIN master..spt_values as b
)
,binCTE
AS
(
SELECT d.id, CAST(CONVERT(binary(4),SUBSTRING(s,n + 1,8),2) AS int) as cblock
FROM (SELECT Id, CONVERT(varchar(max),censusblocks,2) AS s FROM #foo) AS d
JOIN nums_cte
ON n < LEN(d.s)
)
SELECT *
FROM binCTE as b
LEFT
JOIN #censusblock c
ON c.id = b.cblock
ORDER BY b.id, b.cblock
You could also consider adding your existing .Net conversion methods into the database as an assembly and accessing them through CLR functions.
This is off-topic, but I couldn't resist writing these conversions so they use IEnumerables instead of arrays and Lists. This might not be faster per se, but is more general and would allow you to perform the conversion without loading the whole array at once, which may be helpful if the arrays you are dealing with are large.
Here it is, for what it's worth:
static IEnumerable<int> BytesToInts(IEnumerable<byte> bytes) {
var buff = new byte[4];
using (var en = bytes.GetEnumerator()) {
while (en.MoveNext()) {
buff[0] = en.Current;
if (en.MoveNext()) {
buff[1] = en.Current;
if (en.MoveNext()) {
buff[2] = en.Current;
if (en.MoveNext()) {
buff[3] = en.Current;
if (BitConverter.IsLittleEndian)
Array.Reverse(buff);
yield return BitConverter.ToInt32(buff, 0);
continue;
}
}
}
throw new ArgumentException("Wrong number of bytes.", "bytes");
}
}
}
static IEnumerable<byte> IntsToBytes(IEnumerable<int> ints) {
if (BitConverter.IsLittleEndian)
return ints.SelectMany(
b => {
var buff = BitConverter.GetBytes(b);
Array.Reverse(buff);
return buff;
}
);
return ints.SelectMany(BitConverter.GetBytes);
}
Your code seems to like encoding an int into 3 bytes instead of 4, which would cause problems with values that don't fit into 3 bytes (including negatives) - is that intentional?
BTW, you should be able to adapt this (or your) code for execution in SQL Server CLR. This is not exactly "in SQL", but is "in DBMS".
you can use Convert(int, censusBlock) to convert the varchar value to int value.
the you can join on that column.
Or have i misunderstood the question?

Resources