PostgreSQL: How to modify values in view - sql

I have a table I don't want to touch, but from this table I want to create many views that will serve different purposes/analyses.
In one case, I need to change a value based on a condition (-1 become some positive value).
Is it even possible to do that in PostgreSQL?
For example, -1 in the table will become 1 in the view if Col3='B':
+------+------+------+ +------+------+------+
| Col1 | Col2 | Col3 | | Col1 | Col2 | Col3 |
+------+------+------+ > +------+------+------+
| 1 | 3.5 | A | > | 1 | 3.5 | A |
| 2 | -1 | B | > | 2 | 1 | B |
| 3 | -1 | A | | 3 | -1 | A |
+------+------+------+ +------+------+------+

You need to modify the view an put the logic in the query:
select col1,
(case when col3 = 'B' and col2 = -1 then 1 else col2 end) as col2,
col3
from . . .

Related

Skip row that results in zero

Is there a way to skip all rows that result in zero after division. For example
+------+------+
| Col1 | Col2 |
+------+------+
| 5 | 5 |
| 3 | 0 |
| 12 | 6 |
+------+------+
Then col3 = col1 /col2 giving:
+------+------+------+
| Col1 | Col2 | col3 |
+------+------+------+
| 5 | 5 | 1 |
| 12 | 6 | 2 |
+------+------+------+
You can try the below -
select col1, col2, col1/col2
from tablename
where col2!=0

Adding conditional statements to a SQL window function

I want to use a series of conditions to dictate how a window function I have works. Currently, what I have is this:
SELECT col1, col2,
1=Row_number() OVER (PARTITION BY col1 ORDER BY col2 ASC) OR
3=Row_number() OVER (PARTITION BY col1 ORDER BY col2 ASC)
AS col3
FROM myTable;
What it's essentially doing is taking two columns of input, grouping by the values in col1, ordering by values in col2, and then splitting the data for each partition into two halves, and flagging the first row of each half as a true/1.
So, taking this input:
+------+------+
| col1 | col2 |
+------+------+
| 1 | 1 |
| 1 | 2 |
| 1 | 3 |
| 1 | 4 |
| 2 | 1 |
| 2 | 2 |
| 2 | 3 |
| 2 | 4 |
+------+------+
We get this result:
+------+------+------+
| col1 | col2 | col3 |
+------+------+------+
| 1 | 1 | 1 |
| 1 | 2 | 0 |
| 1 | 3 | 1 |
| 1 | 4 | 0 |
| 2 | 1 | 1 |
| 2 | 2 | 0 |
| 2 | 3 | 1 |
| 2 | 4 | 0 |
+------+------+------+
Now, obviously, this only works when there are exactly 4 rows of entries for each value in col1. How do I introduce conditional statements to make this work when there aren't exactly 4 rows?
The constraints I have are these:
a) there will always be an even number of rows (2,4,6..) when grouping by values in `col1`
b) there will be a minimum of 2 rows when grouping by values in `col1`
EDIT:
I think I need to clarify that I do not simply want alternating rows of 1's and 0's. For example, if I used this table instead...
+------+------+
| col1 | col2 |
+------+------+
| 1 | 1 |
| 1 | 2 |
| 1 | 3 |
| 1 | 4 |
| 1 | 5 |
| 1 | 6 |
| 1 | 7 |
| 1 | 8 |
| 2 | 1 |
| 2 | 2 |
| 2 | 3 |
| 2 | 4 |
| 2 | 5 |
| 2 | 6 |
| 2 | 7 |
| 2 | 8 |
+------+------+
...then I'd expect this result:
+------+------+------+
| col1 | col2 | col3 |
+------+------+------+
| 1 | 1 | 1 |
| 1 | 2 | 0 |
| 1 | 3 | 0 |
| 1 | 4 | 0 |
| 1 | 5 | 1 |
| 1 | 6 | 0 |
| 1 | 7 | 0 |
| 1 | 8 | 0 |
| 2 | 1 | 1 |
| 2 | 2 | 0 |
| 2 | 3 | 0 |
| 2 | 4 | 0 |
| 2 | 5 | 1 |
| 2 | 6 | 0 |
| 2 | 7 | 0 |
| 2 | 8 | 0 |
+------+------+------+
In the original example I gave, we grouped by col1 and saw that there were 4 rows for each partition. We take half of that, which is 2, and flag every 2nd row (every other row) as true/1.
In this second example, once we group by col1, we see that there are 8 rows for each partition. Splitting that in half gives us 4, so every 4th row should be flagged with a true/1.
Use modulo arithmetic.
Many dialects of SQL use % for modulus:
SELECT col1, col2,
ROW_NUMBER() OVER (PARTITION BY col1 ORDER BY col2) % 2 as col3
FROM mytable;
Some use the function MOD():
SELECT col1, col2,
MOD(ROW_NUMBER() OVER (PARTITION BY col1 ORDER BY col2), 2) as col3
FROM mytable;
EDIT:
You don't want to alternate rows. You simply want two rows. For that, you can still use modulo arithmetic but with somewhat different logic:
SELECT col1, col2,
(ROW_NUMBER() OVER (PARTITION BY col1 ORDER BY col2) %
FLOOR(COUNT(*) OVER (PARTITION BY col1) / 2)
) as col3
FROM mytable;
I am just extending the Gordon's answer as his answer will not give you correct result -
SELECT col1, col2,
(CASE WHEN ROW_NUMBER() OVER (PARTITION BY col1 ORDER BY col2) %
FLOOR(COUNT(*) OVER (PARTITION BY col1) / 2) = 1 THEN 1 ELSE 0 END
) as col3
FROM mytable;

Round down to nearest of Multiple of N

I have sql table as follows
+-----------------------------+
| |col1 | col2 | col3| col4| |
+-----------------------------+
| _______________________ |
| | a | 3 | d1 | 10 | |
| | a | 6 | d2 | 15 | |
| | b | 2 | d2 | 8 | |
| | b | 30 | d1 | 50 | |
+-----------------------------+
I would like transform the above table into below, where the transformation is
col4 = col4 - (col4 % min(col2) group by col1)
+------------------------------+
| |col1 | col2 | col3| col4| |
+------------------------------+
| ____________________________ |
| |a | 3 | d1 | 9 | |
| |a | 6 | d2 | 15 | |
| |b | 2 | d2 | 8 | |
| |b | 30 | d1 | 50 | |
| |
+------------------------------+
I could read the above table in application code to do transformation manually, was wondering if it was possible to offload the transformation to sql
Just run a simple select query for this:
select col1, col2, col3,
col4 - (col4 % min(col2) over (partition by col1))
from t;
There is no need to actually modify the table.
You can use a multi-table UPDATE to achieve your desired result, joining your table to a table of MIN(col2) values:
UPDATE table1
SET col4 = col4 - (col4 % t2.col2min)
FROM (SELECT col1, MIN(col2) AS col2min
FROM table1
GROUP BY col1) t2
WHERE table1.col1 = t2.col1
Output:
col1 col2 col3 col4
a 3 d1 9
a 6 d2 15
b 2 d2 8
b 30 d1 50
Demo on dbfiddle

Group by random column in ms access

I need something like this in MS ACCESS SQL
SELECT
ID,
col1,
col2,
random(col3)
FROM
table
GROUP BY
ID,
col1,
col2
NOTE:
I want to remove duplicates choosing random value of col3.
INPUT:
+----+------+------+------+
| Id | col1 | col2 | col3 |
+----+------+------+------+
| 1 | A | B | 7 |
+----+------+------+------+
| 1 | A | B | 10 |
+----+------+------+------+
RESULT:
+----+------+------+------+
| Id | col1 | col2 | col3 |
+----+------+------+------+
| 1 | A | B | 7 |
+----+------+------+------+
REQUERY:
+----+------+------+------+
| Id | col1 | col2 | col3 |
+----+------+------+------+
| 1 | A | B | 10 |
+----+------+------+------+

SQL Select for unique value in a column

I have a table like
| ID | COL1 | COL2 |
| 1 | 1 | w |
| 1 | 2 | x |
| 2 | 1 | y |
| 2 | 2 | z |
When I query it, I'd like to get
| ID | COL2:1 | COL2:2 | <--- (when COL1=1 and COL1 =2)
| 1 | w | x |
| 2 | y | z |
I've tried GROUP BY and JOIN for the same table but I get duplicates and not grouped data. I need some pointers for how to get the results I'm expecting.
You can use MAX() and a CASE statement for this:
SELECT ID
,MAX(CASE WHEN Col1 = 1 THEN Col2 END) AS Col2_1
,MAX(CASE WHEN Col1 = 2 THEN Col2 END) AS Col2_2
FROM YourTable
GROUP BY ID
Demo: SQL Fiddle