Get row values as new columns [duplicate] - sql

This question already has answers here:
Create a pivot table with PostgreSQL
(3 answers)
Closed 8 years ago.
I was wondering if it would be possible to get all values of rows with the same ID and present them as new columns, via a query.
For example, if I have the following table:
ID | VALUE
1 | a
1 | b
1 | c
2 | a
2 | b
[...]
I want to present it as:
ID | VALUE1 | VALUE2 | VALUE3 [...]
1 | a | b | c
2 | a | b | -
Thank you for any help

A query wouldn't do it. Unless you do 3 seperate querys.
SELECT ID,VALUE1 FROM Table
SELECT ID,VALUE2 FROM Table
ect...
If you have a problem with your database values not being recursive, then i would set up your table differently.
ID | VALUE
1 | a
1 | b
1 | c
2 | a
2 | b
[...]
You should set up the Table atributes like that rather than your first table.
if you are going to set up your tables differently I would do insert Statements.
INSERT INTO newTable (ID, VALUE)
SELECT ID,VALUE1 FROM oldTable
INSERT INTO newTable (ID, VALUE)
SELECT ID,VALUE2 FROM oldTable
ect..
Another possible way to do it is to display it in your application. Take php for instance.
foreach($sqlArray as $var){
echo $var['id'] ' | ' $var['value1']
echo $var['id'] ' | ' $var['value2']
echo $var['id'] ' | ' $var['value3']
}

Related

PostgreSQL add new not null column and fill with ids from insert statement

I´ve got 2 tables.
CREATE TABLE content (
id bigserial NOT NULL,
name text
);
CREATE TABLE data (
id bigserial NOT NULL,
...
);
The tables are already filled with a lot of data.
Now I want to add a new column content_id (NOT NULL) to the data table.
It should be a foreign key to the content table.
Is it possible to automatically create an entry in the content table to set a content_id in the data table.
For example
**content**
| id | name |
| 1 | abc |
| 2 | cde |
data
| id |... |
| 1 |... |
| 2 |... |
| 3 |... |
Now I need an update statement that creates 3 (in this example) content entries and add the ids to the data table to get this result:
content
| id | name |
| 1 | abc |
| 2 | cde |
| 3 | ... |
| 4 | ... |
| 5 | ... |
data
| id |... | content_id |
| 1 |... | 3 |
| 2 |... | 4 |
| 3 |... | 5 |
demo:db<>fiddle
According to the answers presented here: How can I add a column that doesn't allow nulls in a Postgresql database?, there are several ways of adding a new NOT NULL column and fill this directly.
Basicly there are 3 steps. Choose the best fitting (with or without transaction, setting a default value first and remove after, leave the NOT NULL contraint first and add afterwards, ...)
Step 1: Adding new column (without NOT NULL constraint, because the values of the new column values are not available at this point)
ALTER TABLE data ADD COLUMN content_id integer;
Step 2: Inserting the data into both tables in a row:
WITH inserted AS ( -- 1
INSERT INTO content
SELECT
generate_series(
(SELECT MAX(id) + 1 FROM content),
(SELECT MAX(id) FROM content) + (SELECT COUNT(*) FROM data)
),
'dummy text'
RETURNING id
), matched AS ( -- 2
SELECT
d.id AS data_id,
i.id AS content_id
FROM (
SELECT
id,
row_number() OVER ()
FROM data
) d
JOIN (
SELECT
id,
row_number() OVER ()
FROM inserted
) i ON i.row_number = d.row_number
) -- 3
UPDATE data d
SET content_id = s.content_id
FROM (
SELECT * FROM matched
) s
WHERE d.id = s.data_id;
Executing several statements one after another by using the results of the previous one can be achieved using WITH clauses (CTEs):
Insert data into content table: This generates an integer series starting at the MAX() + 1 value of the current content's id values and has as many records as the data table. Afterwards the new ids are returned
Now we need to match the current records of the data table with the new ids. So for both sides, we use row_number() window function to generate a consecutive row count for each records. Because both, the insert result and the actual data table have the same number of records, this can be used as join criterion. So we can match the id column of the data table with the new content's id values
This matched data can used in the final update of the new content_id column
Step 3: Add the NOT NULL constraint
ALTER TABLE data ALTER COLUMN content_id SET NOT NULL;

Include data in a table looking in every insert if there is a match with the table values

I need to insert data from one table into another, but this insert must look into the table which receives data to determine if there is a match or not, and if it is, don't insert new data.
So, i have the next tables (NODE_ID refers to values in NODE1 and NODE2, think about lines with two nodes everyone):
Table A:
| ARC | NODE1 | NODE2 | STATE |
| x | 1 | 2 | A |
| y | 2 | 3 | A |
| z | 3 | 4 | B |
Table B:
| NODE_ID| VALUE |
| 1 | N |
| 2 | N |
| 3 | N |
| 4 | N |
And want the next result, that relates NODE_ID with ARCS and write in the result table the value of STATE from ARCS table, only one result for each NODE, because if not, i would have more than one row for the same NODE:
Table C result:
| NODE_ID| STATE |
| 1 | A |
| 2 | A |
| 3 |A(or B)|
I tried to do this with CASE statement with EXISTS, IF , and NVL2() and so on in the select but have no result at this time.
Any idea about how could i write this query?
Thank you very much for your help
Ok guys, i edit my message to explain how i did it finally, i've also changed a little bit my first message to make it more clear to undestand because we had problems with that.
So finally i used this query, that #mathguy introduced to me:
merge into Table_C c
using (select distinct b.NODE_ID as nodes, a.STATE
from Table_A a, Table_B b
where (b.NODE_ID=a.NODE1 or b.NODE_ID=a.NODE2) s
on (s.nodes=c.NODE_ID)
when not matched then
insert (NODE_ID, STATE)
values (s.nodes, s.STATE)
That's all
This can be done with insert, but often when you update one table with values from another, the merge statement is more powerful (more flexible).
merge into table_c c
using ( select arc, min(state) as state from table_a group by arc ) s
on (s.arc = c.node_id)
when not matched then insert (node_id, state)
values (s.arc, s.state)
;
Thanks to #Boneist and #ThorstenKettner for pointing out several syntax errors (now fixed).
If table C does not yet exist, use a create select statement:
create table c as select arc as node_id, state from a;
In case there can be duplicate arc (not shown in your sample) you'd need aggregation:
create table c as select arc as node_id, min(state) as state from a group by arc;

TSQL SSRS Cross Reference another column

ID | Col2 | Col3 | SequenceNum
--------------------------------
1 | x | 12 | 5
2 | y | 11 | 6
3 | a | 45 | 7
100 | b | 23 | 8
101 | a | 16 | 9
102 | b | 28 | 10
4 | a | 9 | 11
5 | b | 26 | 12
6 | x | 100 | 13
I have an SSRS report at the moment which you can enter the ID for and it'll show you data for those ID's. For example lets say you enter start ID 2 end ID 5 it'll report back 2,3,4,5 with Col2 and Col3 data.
But what I really want to happen is for it to return 2,3,100,101,102,3,4,5
I believe may be some way to cross reference the SequenceNum column but I'm fairly new to SQL and SSRS can anyone help?
So an user would enter a parameters...
start-ID = 2 which has a SequenceNum of 6
and end-ID = 5 which has an SequenceNum of 12
Extract your starting and ending sequence numbers from value supplied by starting id and ending id respectively and use them in WHERE condition as below
DECLARE #StartingSeqNum INT, #EndingSeqNum
SELECT #StartingSeqNum = SeqNum FROM tableName WHERE ID = #start_id
SELECT #EndingSeqNum = SeqNum FROM tableName WHERE ID = #end_id
SELECT Col2,Col3
FROM tableName
WHERE SeqNum BETWEEN #StartingSeqNum AND #EndingSeqNum
As you are using SSRS you can specify a Value and a Label for your parameters.
Create a dataset with the following SQL as the source:
select distinct ID as Label
,SequenceNum as Value
from YourTable
order by SequenceNum
And then in the properties for your parameter, in Available Values select Get values from query and then select the above dataset. Set the Value field and Label field as your label and value columns and then click OK. You will need to do this for your start and end parameters, using the same dataset.
Your parameters will now be drop down menus that display the ID value to the user, but passes the SequenceNum value to your query. You can then use these to filter your main dataset.

sqlite string replace/delete

I have a column in my database table with name tags which contains comma separated strings and it has records like this-
index | tags
-------------
1 | a,b,c
2 | b
3 | c
4 | z
5 | b,a,c
6 | p,f,w
7 | a,c,b
(for simplicity i am denoting strings with characters)
Now i want to replace/delete particular string.
Delete - say I want to delete b from all rows. If tags column become empty after this operation that row/record should be deleted (index 2 in this case). My records should look like this after this operation.
index | tags
-------------
1 | a,c
3 | c
4 | z
5 | a,c
6 | p,f,w
7 | a,c
Replace - say I want to replace all a with k on original records
index | tags
-------------
1 | k,b,c
2 | b
3 | c
4 | z
5 | b,k,c
6 | p,f,w
7 | k,c,b
Question - I am thinking of using replace function somehow but not sure how to meet above requirement with that. Can i do this in a single sql command? If not please suggest best way to do this (may be multiple sql commands).
I use MSSQL, I'm not sure sqlite. But, you use REPLACE function, like this:
To remove b:
UPDATE Your_Table
SET tags = REPLACE(REPLACE(tags, ',b', ' '), 'b,', ' ')
UPDATE Your_Table
SET tags = NULL WHERE tags = 'b'
To replace a with k:
UPDATE Your_Table
SET tags = REPLACE(tags, 'a', 'k')

Renumber duplicates to make them unique

Table "public.t"
Column | Type | Modifiers
--------+---------+-----------
code | text |
grid | integer |
The codigo column, although of type text, has a numeric sequence which has
duplicates. The grid column is a unique sequence.
select * from t order by grid;
code | grid
------+------
1 | 1
1 | 2
1 | 3
2 | 4
2 | 5
2 | 6
3 | 7
The goal is to eliminate the duplicates in the code column to make it unique. The result should be similar to:
code | grid
------+------
1 | 1
6 | 2
4 | 3
2 | 4
7 | 5
5 | 6
3 | 7
The version is 8.2 (no window functions).
create table t (code text, grid integer);
insert into t values
('1',1),
('1',2),
('1',3),
('2',4),
('2',6),
('3',7),
('2',5);
This is the solution that worked.
drop sequence if exists s;
create temporary sequence s;
select setval('s', (select max(cast(code as integer)) m from t));
update t
set code = i
from (
select code, grid, nextval('s') i
from (
select code, max(grid) grid
from t
group by code
having count(*) > 1
order by grid
) q
) s
where
t.code = s.code
and
t.grid = s.grid
The problem with it is that the update command must be repeated until there are no more duplicates. It is just a "it is not perfect" problem as it is a one time operation only.
Export (and remove) everything but code column (maybe you could subquery for export, and remove just duplicated row). Make code primary with something such auto increment behaviour and reimport everything. code column should be automatically generated.