Iterate through a list to get strings in SQL - sql

I have a SQL table as shown below. I want to generate strings using the 2 fields in my table.
A B
M1 tiger
M1 cat
M1 dog
M3 lion
I want to read in this table, count the number of rows, and store it in string variables like String1 = M1_tiger, String2 = M1_cat, etc. What's the best way to do this?

You could do a concat type query.
SELECT (Table.A + '_' + Table.B) AS A_B, COUNT(*) AS RowsCount FROM Table
I'm asuming the your table name is "Table", the result where you will find the strings you want would be the column named A_B, each record will have two things in each record, one would be the string you asked for, the other column would always be the same thing, the total number of records on you table.
The count part is kinda easy but check this link so you can use the specific count you need: http://www.w3schools.com/sql/sql_func_count.asp

You can try this:
SELECT CONCAT(A, '_', B) FROM yourtable

When you say "read in this table", do you mean read it into a programming language like C#? Or do you want to dynamically create sql variables?
You may want to use a table variable to store your strings rather than individual variables. Regarding getting the row number, you could use something like:
WITH CTE AS
(
SELECT A, B,
ROW_NUMBER() OVER (order by OrderDate) AS 'RowNumber'
FROM MyTable
)
SELECT A,B,RowNumber FROM CTE
See this answer for more on how you may choose to use the table variable.
SQL: Dynamic Variable Names

If your are using Oracle, you can also do it like:
select A ||'_'||B
from yourTable

Solution for PostgreSQL
CREATE SEQUENCE one;
SELECT array_to_string(array_agg(concat('String',nextval('one'),' = ',A,'_',B)), ', ')
AS result
FROM test_table;
DROP SEQUENCE one;
Explanation:
Create a temporary sequence 'one' in order to use nextval function.
nextval('sequence') - advance sequence and return new value.
concat('input1', ...) - concatenate all arguments.
array_agg('input1', ...); - input values, including nulls,
concatenated into an array.
array_to_string('array', 'delimiter') - concatenates array elements
using supplied delimiter and optional null string.
Drop the sequence 'one'.
The output of the query (for two test rows in test_table):
result
-------------------------------------------
String1 = M1_tiger, String2 = M1_cat
(1 row)

Related

How do I create a column in postgresql to count different values in the same cells of a column that are in varchar format?

How do I count different values in a cell of a column and put that count in a new column?
for example :
car/bike/truck/pickup/trailer/jeep
I want to be able to create a column like 'count of vehicle' with a corresponding value of 6. This is Postgres by the way
You can count different values by SELECT COUNT(DISTINCT vehicle) FROM table; and set some value to column by UPDATE table SET different = val.
You can turn that value into an array, then count the number of array elements:
select cardinality(string_to_array(the_column, '/')) as vehicle_count
from the_table
You can capture the names between slashes as a set using a regular expression. Then, you can count the size of the set.
For example:
select count(*) from (
select regexp_matches('car/bike/truck/pickup/trailer/jeep',
'([^/]+)', 'g')
) x
Result:
count
-----
6
See running example at db<>fiddle.

How to select a column whose name is a value in another column in POSTGRESQL?

I know this isn't valid SQL, but I'd like to do something like:
SELECT items.{SELECT items.preferred_column}
To elaborate, to achieve what I'm trying to achieve, I could write a long case when statement:
SELECT
CASE WHEN items.preferred_column = "column_a" THEN items.column_a
CASE WHEN items.preferred_column = "column_b" THEN items.column_b
CASE WHEN items.preferred_column = "column_c" THEN items.column_c
... and so on...
But that seems wrong. I would prefer to write a query that looks at the value of items.preferred_column and loads that column.
Is this possible?
My use case involves an Active Record (the ORM for Rails) query, which limits me. I'm not able to use "INTO" for example.
Doing this without creating a SQL function would preferred, though if it's not possible without creating a SQL function that would be good to know.
Thanks in advance for lending your expertise!
You can try transforming the table rows with row_to_json() and then using json_each(), you can join the resultant "key" field on the preferred_column:
WITH CTE AS (
SELECT
row_to_json(Z.*)::jsonb as rcr,
row_number() over(partition by null order by <whatever comparator clause>) as rn,
Z.*
FROM items Z)
SELECT b.value, a.*
FROM CTE a, jsonb_each(rcr) b, CTE c
WHERE c.rn=a.rn AND b.key = ( c.preferred_column )
Note that this essentially operates as a quasi-pivot, so you'll need to maintain an index (the row_number invocation) to self-join the table when extracting the appropriate key-value pairs from jsonb_each's set-return. Casting to jsonb will be helpful in that the binary form will alphabetize the key-value pairs by key order within the object itself.
If you need to get the resultant value as a text string instead of a json primitive, you can do
b.value #>>'{}'
instead of using jsonb_each_text(), which will preserve any json columns.

Get maximum value in a column in sql query if the column is alphanumeric

This is the table which I have by name project and it contains 3 columns:
estimateId
name
projectName
I want to fetch data from SQL database based on maximum value of estimateId
but here estimateid is alphanumeric. How can I achieve this.
I need a SQL query to achieve this:
For example estimateId contains values like:
Elooo1
Elooo2
......
Elooo10
and so on. So how can I achieve this?
Setup Testing Data
DECLARE #tmpTable TABLE ( estimateId NVARCHAR(MAX));
INSERT into #tmpTable(estimateId) VALUES ('Elooo1'),('Elooo2'),('Elooo3'),('Elooo4'),('Elooo5'),('Elooo6');
Split data based on the pattern
SELECT T.prefix AS prefix, MAX(T.suffix) AS suffix, MAX(estimateId) AS estimateId FROM (SELECT estimateId,LEFT(estimateId, PATINDEX('%[a-zA-Z][^a-zA-Z]%', estimateId )) AS prefix,LTRIM(RIGHT(estimateId, LEN(estimateId) - PATINDEX('%[a-zA-Z][^a-zA-Z]%', estimateId ))) As suffix FROM #tmpTable) T GROUP BY T.prefix
Result
prefix suffix estimateId
Elooo 6 Elooo6
Reference
split alpha and numeric using sql
I just started SQL like today.. so i'm totally a newbie, but I think I could solve your problem. I would do something like this
SELECT name, projectName FROM table ORDER BY estimateId ASC
or (I think you will need ORDER BY ... DESC)
SELECT name, projectName FROM table ORDER BY estimateId DESC
You seem to be looking to extract the numeric part of the strings. Assuming that the strings have variable length, and that the numbers are always at the end, you can do:
try_cast(
substring(estimateId, patindex('%[0-9]%', estimateId), len(estimateId))
as int
)
This captures everything from the the first number in the string to the end of the string, and attempts to convert it to a number (if the conversion fails, try_cast() returns null rather than raising an error).
It is not very clear what you want to use this information for. For example, if you wanted to sort your data accordingly, you would do:
select *
from mytable
order by try_cast(
substring(estimateId, patindex('%[0-9]%', estimateId), len(estimateId))
as int
)

Check if value is in different table

so I am new to SQL and I have little experience with it. So please excuse if this is really basic but I can't seem to find it after googling...
so I have a table which contains a serialnumber field.
I have a single inputfield which contains comma seperated values with each one being a serialnumber. I just want to display the serialnumbers that are in that comma seperated string.
So I have a splitstring function that I can use which splits the string at the commas like this:
SELECT * FROM dbo.SplitString('sn1,sn2,sn3,sn4,sn5,sn6', ',')
this returns a table with each sn being a row.
So I would want something like this:
SELECT
*
FROM
tbl_serials AS sn
WHERE
sn.serialnumber in dbo.SplitString('sn1,sn2,sn3,sn4,sn5,sn6', ',')
so this would display only the rows where the serialnumber is inside the string. But I don't know how to syntactily construct this.
Any help is appreciated
One method to do this is using join:
SELECT sn.*
FROM tbl_serials sn JOIN
dbo.SplitString('sn1,sn2,sn3,sn4,sn5,sn6', ',') as ss(val)
ON sn.serialnumber = ss.val;
With your route, you need a subquery:
SELECT sn.*
FROM tbl_serials sn JOIN
WHERE sn.serialnumber in (SELECT val
FROM dbo.SplitString('sn1,sn2,sn3,sn4,sn5,sn6', ',') as ss(val)
);
In both these cases, the as ss(val) assigns a table alias and a column alias to the value. Some versions of SplitString might return more than one value (such as a position). If you have such a version, then you need to include the extra return values as named columns.

Compare comma separated list with individual row in table

I have to compare comma separated values with a column in the table and find out which values are not in database. [kind of master data validation]. Please have a look at the sample data below:
table data in database:
id name
1 abc
2 def
3 ghi
SQL part :
Here i am getting comma separated list like ('abc','def','ghi','xyz').
now xyz is invalid value, so i want to take that value and return it as output saying "invalid value".
It is possible if i split those value, take it in temp table, loop through each value and compare one by one.
but is there any other optimal way to do this ??
I'm sure if I got the question right, however, I would personally be trying to get to something like this:
SELECT
D.id,
CASE
WHEN B.Name IS NULL THEN D.name
ELSE "invalid value"
END
FROM
data AS D
INNER JOIN badNames B ON b.Name = d.Name
--as SQL is case insensitive, equal sign should work
There is one table with bad names or invalid values if You prefer. This can a temporary table as well - depending on usage (a black-listed words should be a table, ad hoc invalid values provided by a service should be temp table, etc.).
NOTE: The select above can be nested in a view, so the data remain as they were, yet you gain the correctness information. Otherwise I would create a cursor inside a function that would go through the select like the one above and alter the original data, if that is the goal...
It sounds like you just need a NOT EXISTS / LEFT JOIN, as in:
SELECT tmp.InvalidValue
FROM dbo.HopeThisIsNotAWhileBasedSplit(#CSVlist) tmp
WHERE NOT EXISTS (
SELECT *
FROM dbo.Table tbl
WHERE tbl.Field = tmp.InvalidValue
);
Of course, depending on the size of the CSV list coming in, the number of rows in the table you are checking, and the style of splitter you are using, it might be better to dump the CSV to a temp table first (as you mentioned doing in the question).
Try following query:
SELECT SplitedValues.name,
CASE WHEN YourTable.Id IS NULL THEN 'invalid value' ELSE NULL END AS Result
FROM SplitedValues
LEFT JOIN yourTable ON SplitedValues.name = YourTable.name