I know there are similar questions on SO but I wasn't able to find my exact use case. I am trying to duplicate some rows in a PostgreSQL table and change one value in them. For example, I have a table with three values and I want to grab a selection of rows based on the third value and copy them, then change the third value. Here's what I have so far:
INSERT INTO my_table ( val1, val2, val3 )
VALUES
(
( SELECT val1 FROM my_table WHERE val3 = '1' LIMIT 2, ( SELECT val2 FROM my_table WHERE val3 = '1' LIMIT 2), '2' )
I am getting an error that says "more than one row returned by a subquery used as an expression". Also, I would like to be able to test the solution with just a couple rows, so ideally I would be able to limit the SELECT statements to just a couple. Is this possible?
The VALUES keyword is used when you're inserting manual values into the table. If you want to insert based on a query, you skip that.
INSERT INTO my_table (val1, val2, val3)
SELECT val1, val2, '2'
FROM my_table
WHERE val3 = '1'
LIMIT 2;
I have a table in pgadmin (old verion pgadmin3) of the following format. Please note the commas at the beginning and the end of the values
my_table
id column_name
1 , val1,
2 , val1, val2,
3 , val2, val4, val5,
id
column_name
1
, val1,
2
, val1, val2,
3
, val2, val4, val5,
I would like to get the following output
expected outcome
new_id column_name
1 val1
2 val2
3 val4
4 val5
new_id
column_name
1
val1
2
val2
3
val4
3
val5
So basically I want the output to be of distinct values.
I have been trying a different scripts with no success. (Please again note the commas at the beginning and at the end of the strings in that column. They need to be removed too in the process)
Can you please help me on this.
Thank you,
Shaun
Split the string and discard the empty strings. Then, for each value, take the lowest matching id.
SELECT DISTINCT ON (c.c)
m.id, c.c
FROM mytab AS m
CROSS JOIN LATERAL regexp_split_to_table(m.column_name, ', *') AS c(c)
WHERE c.c <> ''
ORDER BY c.c, m.id;
id | c
----+------
1 | val1
2 | val2
3 | val4
3 | val5
(4 rows)
First normalize the data by splitting my_column into rows (this is the t CTE) and then select distinct values. trim function is used twice to clean the commas and spaces from the list string.
with t as
(
select id, l.list_item
from my_table m
cross join lateral
(
select trim(s) as list_item
from unnest(string_to_array(trim(m.column_name, ', '), ',')) s
) l
)
select distinct on (list_item) id, list_item as column_name
from t
order by list_item, id;
DB2 V9 z/os
Background: I have a 4 column table defined as (col1 int, col2 smallint, col3 int, col4 date)
Row 1 has values of (1,123,456,2012-08-23)
When I execute the following:
SELECT CAST(col2 AS VARCHAR(5)) CONCAT CAST(col3 AS VARCHAR(5))
FROM db.T1
WHERE col1 = 1;
Value 123456 is returned, which is exactly what i want.
When I execute the following:
UPDATE db.table2
SET col3 = SELECT CAST(col2 AS VARCHAR(5)) CONCAT CAST(col3 AS VARCHAR(5))
FROM db.T1
WHERE col1 = 1;
Error is:
SQL0408N A value is not compatible with the data type of its assignment target. Target name is "col3". SQLSTATE=42821
I understand the error is due to attempting to insert a varchar into an integer. What else can I do? I've tried using various CAST statements but cannot get a value to insert into col3. i need the value to appear joined as shown above.
Any help would be appreciated.
Wrapping all of the casts as a final cast( ... as integer) should work:
UPDATE db.table2
SET col3 = SELECT CAST(
CAST(col2 AS VARCHAR(5)) CONCAT CAST(col3 AS VARCHAR(5))
AS INTEGER)
FROM db.T1
WHERE col1 = 1;
depend on the MAXIMUM value of your small integers,
you can convert them to base-9,
then concatenate with '9'.
CONCAT( IFNULL(CONV(sint1, 10, 9),''),
'9',
IFNULL(CONV(tint2, 10, 9),'')
) AS combined
and another option, ALSO depend on the MAXIMUM value of your small integers,
to PAD-LEFT with zeros one of them.
CONCAT(
sint1,
LPAD(tint2,3,0)
) AS combined
See full code and explanation: https://mdb-blog.blogspot.com/2021/10/mysql-joincombine-2-smallinttinyint.html
From the table below, how can I convert the Values column into multiple columns, populated with individual values that are currently separated by commas? Before the conversion:
Name Values
---- ------
John val,val2,val3
Peter val5,val7,val9,val14
Lesli val8,val34,val36,val65,val71,val
Amy val3,val5,val99
The result of the conversion should look like:
Name Col1 Col2 Col3 Col4 Col5 Col6
---- ---- ---- ---- ---- ---- ----
John val val2 val3
Peter val5 val7 val9 val14
Lesli val8 val34 val36 val65 val71 val
Amy val3 val5 val99
First, what database product and version are you using? If you are using SQL Server 2005 and later, you can write a Split user-defined function like so:
CREATE FUNCTION [dbo].[Split]
(
#DelimitedList nvarchar(max)
, #Delimiter varchar(2) = ','
)
RETURNS TABLE
AS
RETURN
(
With CorrectedList As
(
Select Case When Left(#DelimitedList, DataLength(#Delimiter)) <> #Delimiter Then #Delimiter Else '' End
+ #DelimitedList
+ Case When Right(#DelimitedList, DataLength(#Delimiter)) <> #Delimiter Then #Delimiter Else '' End
As List
, DataLength(#Delimiter) As DelimiterLen
)
, Numbers As
(
Select TOP (Coalesce(Len(#DelimitedList),1)) Row_Number() Over ( Order By c1.object_id ) As Value
From sys.objects As c1
Cross Join sys.columns As c2
)
Select CharIndex(#Delimiter, CL.list, N.Value) + CL.DelimiterLen As Position
, Substring (
CL.List
, CharIndex(#Delimiter, CL.list, N.Value) + CL.DelimiterLen
, CharIndex(#Delimiter, CL.list, N.Value + 1)
- ( CharIndex(#Delimiter, CL.list, N.Value) + CL.DelimiterLen )
) As Value
From CorrectedList As CL
Cross Join Numbers As N
Where N.Value < Len(CL.List)
And Substring(CL.List, N.Value, CL.DelimiterLen) = #Delimiter
)
You can then split out the values in you want using something akin to:
Select Name, Values
From Table1 As T1
Where Exists (
Select 1
From Table2 As T2
Cross Apply dbo.Split (T1.Values, ',') As T1Values
Cross Apply dbo.Split (T2.Values, ',') As T2Values
Where T2.Values.Value = T1Values.Value
And T1.Name = T2.Name
)
Here is a solution that uses a recursive cte to generate a "table of numbers" (courtesy of Itzik Ben-Gan), which is useful for all manner of problems including string splitting, and PIVOT. SQL Server 2005 onwards. Full table create, insert and select script included.
CREATE TABLE dbo.Table1
(
Name VARCHAR(30),
[Values] VARCHAR(128)
)
GO
INSERT INTO dbo.Table1 VALUES ('John', 'val,val2,val3')
INSERT INTO dbo.Table1 VALUES ('Peter', 'val5,val7,val9,val14')
INSERT INTO dbo.Table1 VALUES ('Lesli', 'val8,val34,val36,val65,val71,val')
INSERT INTO dbo.Table1 VALUES ('Amy', 'val3,val5,val99')
GO
SELECT * FROM dbo.Table1;
GO
WITH
L0 AS(SELECT 1 AS c UNION ALL SELECT 1),
L1 AS(SELECT 1 AS c FROM L0 AS A, L0 AS B),
L2 AS(SELECT 1 AS c FROM L1 AS A, L1 AS B),
L3 AS(SELECT 1 AS c FROM L2 AS A, L2 AS B),
Numbers AS(SELECT ROW_NUMBER() OVER(ORDER BY c) AS n FROM L3)
SELECT Name, [1] AS Column1, [2] AS Column2, [3] AS Column3, [4] AS Column4, [5] AS Column5, [6] AS Column6, [7] AS Column7
FROM
(SELECT Name,
ROW_NUMBER() OVER (PARTITION BY Name ORDER BY nums.n) AS PositionInList,
LTRIM(RTRIM(SUBSTRING(valueTable.[Values], nums.n, charindex(N',', valueTable.[Values] + N',', nums.n) - nums.n))) AS [Value]
FROM Numbers AS nums INNER JOIN dbo.Table1 AS valueTable ON nums.n <= CONVERT(int, LEN(valueTable.[Values])) AND SUBSTRING(N',' + valueTable.[Values], n, 1) = N',') AS SourceTable
PIVOT
(
MAX([VALUE]) FOR PositionInList IN ([1], [2], [3], [4], [5], [6], [7])
) AS Table2
GO
--DROP TABLE dbo.Table1
Which converts this output
Name Values
John val,val2,val3
Peter val5,val7,val9,val14
Lesli val8,val34,val36,val65,val71,val
Amy val3,val5,val99
to
Name Column1 Column2 Column3 Column4 Column5 Column6 Column7
Amy val3 val5 val99 NULL NULL NULL NULL
John val val2 val3 NULL NULL NULL NULL
Lesli val8 val34 val36 val65 val71 val NULL
Peter val5 val7 val9 val14 NULL NULL NULL