This question already has answers here:
Split column into multiple rows in Postgres
(3 answers)
Closed 8 days ago.
I have a question how to put number in each column.
Right now, the data is looking like this.
Column A
Column B
1
1, 2, 3, 4, 5, 6, 8, 10
2
4, 6, 7, 9, 11, 12
My goal is making this table look like this below.
Column A
Column B
1
1
1
2
1
3
1
4
etc.
create table pp
(
id int,
toppings int);
insert into pp
(id, toppings)
values
(1,1),
(1,2),
(1,3),
(1,4),
(1,5),
(1,6),
(1,8),
(1,10),
(2,4),
(2,6),
(2,7),
(2,9),
(2,11),
(2,12);
I know this work but I'm looking for an easier way.
select a, unnest(b)
from pp;
unnest() transforms an array into a set of rows.
Here is the documentation.
And here is the demo.
Related
Let's say I have a very basic table:
DAY_ID
Value
Inserts
5
8
2
4
3
0
3
3
0
2
4
1
1
8
0
I want to be able to "loop" through the Inserts column, and add that many # of rows.
For each added row, I want DAY_ID to be decreased by 1 and Value to remain the same, Inserts column is irrelevant we can set to 0.
So 2 new rows should be added from DAY_ID = 5 and Value = 8, and 1 new row with DAY_ID = 2 and Value = 4. The final output of the new rows would be:
DAY_ID
Value
Inserts
(5-1)
8
0
(5-2)
8
0
(2-1)
4
0
I haven't tried much in SQL Server, I was able to create a solution in R and Python using arrays, but I'm really hoping I can make something work in SQL Server for this project.
I think this can be done using a loop in SQL.
Looping is generally not the way you solve any problems in SQL - SQL is designed and optimized to work with sets, not one row at a time.
Consider this source table:
CREATE TABLE dbo.src(DAY_ID int, Value int, Inserts int);
INSERT dbo.src VALUES
(5, 8, 2),
(4, 3, 0),
(3, 3, 0),
(2, 4, 1),
(1, 8, 0);
There are many ways to "explode" a set based on a single value. One is to split a set of commas (replicated to the length of the value, less 1).
-- INSERT dbo.src(DAY_ID, Value, Inserts)
SELECT
DAY_ID = DAY_ID - ROW_NUMBER() OVER (PARTITION BY DAY_ID ORDER BY ##SPID),
src.Value,
Inserts = 0
FROM dbo.src
CROSS APPLY STRING_SPLIT(REPLICATE(',', src.Inserts-1), ',') AS v
WHERE src.Inserts > 0;
Output:
DAY_ID
Value
Inserts
1
4
0
4
8
0
3
8
0
Working example in this fiddle.
I have a table in SQL with a structure like:
ID_COL
VALUE_1
VALUE_2
VALUE_3
A
2
4
3
A
3
2
5
B
2
8
6
B
4
7
6
B
3
2
1
C
7
9
6
...
...
...
...
For each distinct ID_COL value (A, B, C, etc.) I need to add a row. Every row being inserted will have the same values for the VALUE_X columns. For example, I'll add a row with values A, 1, 2, 3, B, 1, 2, 3, etc.
Is there any way to do this programmatically in SQL without having to generate a bunch of separate insert statements? I'm not super familiar with SQL, but in another language like Python I would do a for-each loop on the distinct ID_COL values.
If it makes a difference, this is in SQL Server.
Thanks!
There is no need to resort to looping for this kind of thing. Your question is lacking any real details about your table or what you really want to accomplish. So assuming you want the value 1, 2, 3 along with each distinct value of ID_COL it would be something like this.
insert YourTable
select distinct ID_COL
, 1
, 2
, 3
from YourTable
I want to write a bigquery query to get values of a column which is the sum of values of another column, based on a "like" condition.
In the below table column starts_with_count is what I want to fill. I have added the expected values for this column manually to show my expectation. Other column values are already present.
The starts_with_count value is sum (full_count) where its link appears in other rows.
company
link
full_count
starts_with_count (expected)
abc
http://www.abc.net1
1
15 (= sum (full_count) where link like 'http://www.abc.net1%')
abc
http://www.abc.net1/page1
2
9 (= sum (full_count) where link like 'http://www.abc.net1/page1%')
abc
http://www.abc.net1/page1/folder1
3
3 (= sum (full_count) where link like 'http://www.abc.net1/page1/folder1%')
abc
http://www.abc.net1/page1/folder2
4
4
abc
http://www.abc.net1/page2
5
5
xyz
http://www.xyz.net1/
6
21
xyz
http://www.xyz.net1/page1/
7
15
xyz
http://www.xyz.net1/page1/file1
8
8
Try this:
WITH sample AS (
SELECT * FROM UNNEST([
STRUCT('abc' AS company, 'http://www.abc.net1' AS link, 1 AS full_count),
('abc', 'http://www.abc.net1/page1', 2),
('abc', 'http://www.abc.net1/page1/folder1', 3),
('abc', 'http://www.abc.net1/page1/folder2', 4),
('abc', 'http://www.abc.net1/page2', 5),
('xyz', 'http://www.xyz.net1/', 6),
('xyz', 'http://www.xyz.net1/page1/', 7),
('xyz', 'http://www.xyz.net1/page1/file1', 8)
])
)
SELECT first.company, first.link, SUM(second.full_count) AS starts_with_count
FROM sample first, sample second
WHERE STARTS_WITH(second.link, first.link)
GROUP BY 1, 2
;
output:
Another option
select * except(links),
( select sum(full_count)
from t.links
where starts_with(link, t.link)
) starts_with_count
from (
select *,
array_agg(struct(link, full_count)) over(partition by company) links
from your_table
) t
if applied to sample data in your question - output is
For the simple/dummy example you provided - performance improvement is significant!
Which one to use really depends on your real data!
To analyze - use EXECUTION DETAILS tab
My Table contain Experience Field which is an integer . and my page contains a check box list like 0-3,3-7,7-9,9-12,12-15,15+ years and i have to filter this from table using select query i have tried between but it is not working when multiple fields selected can any one help
my table structure is like
Name Experience in year
---- ---------
a 1
b 2
c 3
d 5
e 2
f 1
My parameter for database is a varchar string
if we select 0-3years then '0-3'
if we select 3-6years then '3-6'
if we select both then '0-3,3-6'
if we select 0-3years and 9-12years then '0-3,9-12'
Now i am sending Data in these format i dont know it is a good method please show me the better way
First you need a table checkRanges
CREATE TABLE checkRanges
([checkID] int, [name] varchar(8), [low] int, [upper] int);
INSERT INTO checkRanges
([checkID], [name], [low], [upper])
VALUES
(1, '0-3', 0, 2),
(2, '3-6', 3, 5),
(4, '6-9', 6, 8),
(8, '9-12', 9, 11),
(16, '12+', 12, 999)
See how checkID are power of 2?
In your app if user select 3-6 and 9-12 you send 2+8 = 10 to your db. Also would be great if you create your check box using the db info.
In your db you do bitwise comparasion to select the right ranges.
Then perfom the between with each range.
WITH ranges as (
SELECT *
FROM checkRanges
where checkID & 10 > 0
)
SELECT *
FROM users u
inner join ranges r
on u.Experience between r.low and r.upper
See it all together SQL Fiddle Demo
I include more users. You only have to change the clausule where checkID & 10 > 0 to test other combination.
NOTE:
I update the ranges. Change the upper value to value - 1 because between is inclusive and could give duplicate results.
If want use old version you have to replace the betwewen in the join sentence to
u.Experience >= r.low and u.Experience *<* r.upper
I have a column COL in a table which has integer values like: 1, 2, 3, 10, 11 ... and son on. Uniqueness in the table is created by an ID. Each ID can be associated with multiple COL values. For example
ID | COL
——————————
1 | 2
————+—————
1 | 3
————+—————
1 | 10
————+—————
is valid.
What I want to do is select only the COL values from the table that are greater than 3, AND (the problematic part) also select the value that is the MAX of 1, 2, and 3, if they exist at all. So in the table above, I would want to select values [3, 10] because 10 is greater than 3 and 3 = MAX(3, 2).
I know I can do this with two SQL statements, but it's sort of messy. Is there a way of doing it with one statement only?
SELECT col FROM table
WHERE
col > 3
UNION
SELECT MAX(col) FROM table
WHERE
col <= 3
This query does not assume you want the results per id, because you don't explicitely mention it.
I don't think you need pl/sql for this, SQL is enough.