Select substring from a column in SQL - sql

How do I match a substring on another table?
Table 1:
Reference | Value
----------+-------
1 | 02.02.2011 07:07:00 498-123456-741
5 | 123-789654-100
5 | 123-789654-100
Table 2:
Reference | Code
----------+-------
5 | 123-789654-700
1 | 498-123456-100
I want to count the value from table one on table 2
select count(value) as count
from table 1 join table 2 on substring(value,0,12)=substring(code,0,12)
where reference='5'
If it the value is present in Table 2 it gives me a count of 2.
select count(value) as count
from table 1 join table 2 on substring(value,20,12)=substring(code,0,12)
where reference='1'
So the first query works fine the second query when a value comes in like 02.02.2011 07:07:00 498-123456-741 it doesn't compare it to table to even though that value is there, in Table 2 it will always be a substring of (0,12).

The syntax is like this : SUBSTRING ( expression ,start , length )
For example :
SELECT x = SUBSTRING('abcdef', 2, 3);
Here is the result set:
x
----------
bcd
You should do like this :
select count(*) as count from
table 1 join table 2
on substring(value,20,12)=substring(code,0,12)

Do this
SELECT SUBSTRING('w3resource', startingIndex, lengthForRequiredString);
Example
SELECT SUBSTRING(column_name, 4, 3);

Related

PostgreSQL CTE UPDATE-FROM query skips rows

2 tables
table_1 rows: NOTE: id 2 has two rows
-----------------------
| id | counts | track |
-----------------------
| 1 | 10 | 1 |
| 2 | 10 | 2 |
| 2 | 10 | 3 |
-----------------------
table_2 rows
---------------
| id | counts |
---------------
| 1 | 0 |
| 2 | 0 |
---------------
Query:
with t1_rows as (
select id, sum(counts) as counts, track
from table_1
group by id, track
)
update table_2 set counts = (coalesce(table_2.counts, 0) + t1.counts)::float
from t1_rows t1
where table_2.id = t1.id;
select * from table_2;
When i ran above query i got table_2 output as
---------------
| id | counts |
---------------
| 1 | 10 |
| 2 | 10 | (expected counts as 20 but got 10)
---------------
I noticed that above update query is considering only 1st match and skipping rest.
I can make it work by changing the query like below. Now the table_2 updates as expected since there are no duplicate rows from table_1.
But i would like to know why my previous query is not working. Is there anything wrong in it?
with t1_rows as (
select id, sum(counts) as counts, array_agg(track) as track
from table_1
group by id
)
update table_2 set counts = (coalesce(table_2.counts, 0) + t1.counts)::float
from t1_rows t1
where table_2.id = t1.id;
Schema
CREATE TABLE IF NOT EXISTS table_1(
id varchar not null,
counts integer not null,
track integer not null
);
CREATE TABLE IF NOT EXISTS table_2(
id varchar not null,
counts integer not null
);
insert into table_1(id, counts, track) values(1, 10, 1), (2, 10, 2), (2, 10, 3);
insert into table_2(id, counts) values(1, 0), (2, 0);
The problem is that an UPDATE in PostgreSQL creates a new version of the row rather than changing the row in place, but the new row version is not visible in the snapshot of the current query. So from the point of view of the query, the row “vanishes” when it is updated the first time.
The documentation says:
When a FROM clause is present, what essentially happens is that the target table is joined to the tables mentioned in the from_list, and each output row of the join represents an update operation for the target table. When using FROM you should ensure that the join produces at most one output row for each row to be modified. In other words, a target row shouldn't join to more than one row from the other table(s). If it does, then only one of the join rows will be used to update the target row, but which one will be used is not readily predictable.
So if I read your question correctly, you expect row 2&3 from table_1 to get added together? If so, the reason your first approach didn't work is because it grouped by id, track.
Since row 2&3 have a different number in the track column, they didn't get added together by the group by clause.
Your second approach worked because it only grouped by id

Average of successive pairs of rows

I have a table like so:
id | value
---+------
1 | 10
2 | 5
3 | 11
4 | 8
5 | 9
6 | 7
The data in this table is really pairs of values, which I need to take the average of, which should result in:
pair_id | pair_avg
--------+---------
1 | 7.5
2 | 9.5
3 | 8
I have got some other information (a pair of flags) which could also help to pair them, though they still have to be in id order. I cannot really change how the data comes to me.
As I'm more used to arrays than SQL, all I can think is that I need to loop through the table and sum the pairs. But this doesn't strike me as very SQL-ish.
Update
In making this minimal example, I have apparently over simplified.
As the table I am working with is the result of several selects, the IDs will not be quite so clean, apologies for not specifying this.
The table looks a lot more like:
id | value
----------
1 | 10
4 | 5
6 | 11
7 | 8
10 | 9
15 | 7
The results will be used to create a second table, I don't care about the index on this new table, it can provide its own, therefore giving the result already indicated above.
If your data is as clean as the question makes it seem: no NULL values, no gaps, pairs have consecutive positive numbers, starting with 1, and assuming id is type integer, it can be as simple as:
SELECT (id+1)/2 AS pair_id, avg(value) AS pair_avg
FROM tbl
GROUP BY 1
ORDER BY 1;
Integer division truncates the result and thus takes care of grouping pairs automatically this way.
If your id numbers are not as regular but at least strictly monotonically increasing like your update suggests (still no NULL or missing values), you can use a surrogate ID generated with row_number() instead:
SELECT id/2 AS pair_id, avg(value) AS pair_avg
FROM (SELECT row_number() OVER (ORDER BY id) + 1 AS id, value FROM tbl) t
GROUP BY 1
ORDER BY 1;
db<>fiddle here
I think you can just use group by with arithmetic:
select row_number() over (order by min(id)), min(id), max(id), avg(id)
from t
group by floor( (id - 1) / 2 );
I'm not sure why you would want to renumber the ids after aggregation. The original ids seem more useful.
You may use ceil function by appliying division by 2 to id column as in the following select statement :
with t(id,value) as
(
select 1 , 10 union all
select 2 , 5 union all
select 3 , 11 union all
select 4 , 8 union all
select 5 , 9 union all
select 6 , 7
)
select ceil(id/2::numeric) as "ID", avg(t.value) as "pair_avg"
from t
group by "ID"
order by "ID";
id | pair_avg
-------------
1 | 7.5
2 | 9.5
3 | 8

Count results in SQL statement additional row

I am trying to get 3% of total membership which the code below does, but the results are bringing me back two rows one has the % and the other is "0" not sure why or how to get rid of it ...
select
sum(Diabetes_FLAG) * 100 / (select round(count(medicaid_no) * 0.03) as percent
from membership) AS PERCENT_OF_Dia
from
prefinal
group by
Diabetes_Flag
Not sure why it brought back a second row I only need the % not the second row .
Not sure what I am doing wrong
Output:
PERCENT_OF_DIA
1 11.1111111111111
2 0
SELECT sum(Diabetes_FLAG)*100 / (SELECT round(count(medicaid_no)*0.03) as percentt
FROM membership) AS PERCENT_OF_Dia
FROM prefinal
WHERE Diabetes_FLAG = 1
# GROUP BY Diabetes_Flag # as you're limiting by the flag in the where clause, this isn't needed.
Remove the group by if you want one row:
select sum(Diabetes_FLAG)*100/( SELECT round(count(medicaid_no)*0.03) as percentt
from membership) AS PERCENT_OF_Dia
from prefinal;
When you include group by Diabetes_FLAG, it creates a separate row for each value of Diabetes_FLAG. Based on your results, I'm guessing that it takes on the values 0 and 1.
Not sure why it brought back a second row
This is how GROUP BY query works. The group by clause group data by a given column, that is - it collects all values of this column, makes a distinct set of these values and displays one row for each individual value.
Please consider this simple demo: http://sqlfiddle.com/#!9/3a38df/1
SELECT * FROM prefinal;
| Diabetes_Flag |
|---------------|
| 1 |
| 1 |
| 5 |
Usually GROUP BY column is listed in in SELECT clause too, in this way:
SELECT Diabetes_Flag, sum(Diabetes_Flag)
FROM prefinal
GROUP BY Diabetes_Flag;
| Diabetes_Flag | sum(Diabetes_Flag) |
|---------------|--------------------|
| 1 | 2 |
| 5 | 5 |
As you see, GROUP BY display two rows - one row for each unique value of Diabetes_Flag column.
If you remove Diabetes_Flag colum from SELECT clause, you will get the same result as above, but without this column:
SELECT sum(Diabetes_Flag)
FROM prefinal
GROUP BY Diabetes_Flag;
| sum(Diabetes_Flag) |
|--------------------|
| 2 |
| 5 |
So the reason that you get 2 rows is that Diabetes_Flag has 2 distict values in the table.

How to merge two column with same data type of a table into one column using PostgreSql

I have found lots of answer to merge two column into one, but I want something like below:
I have a table named A
id_one | id_two
---------------
1 | 3
3 | 9
3 | 6
I want to combine these two column into one like
id
----
1
3
9
6
use Union to combine the two column which also removes duplicates
select id_one from yourtable
union
select id_two from yourtable

Create view with multiple rows for one source row

I have a table which has an offset and a qty column.
I now want to create a view from that which has an entry for each precise position.
Table:
offset | qty | more_data
-------+---------+-------------
1 | 3 | 'qwer'
2 | 2 | 'asdf'
View:
position | more_data
---------+------------
1 | 'quer'
2 | 'quer'
3 | 'quer'
2 | 'asdf'
3 | 'asdf'
Is that even possible?
I would need to do that for Oracle (8! - 11), MS SQL (2005-) and PostgreSQL (8-)
Based on you input/output:
with t(offset, qty) as (
select 1, 3 from dual
)
select offset + level - 1 position
from t
connect by rownum <= qty
POSITION
--------
1
2
3
For Postgres:
select offst, generate_series(offst, qty) as position
from the_table
order by offst, num;
SQLFiddle: http://sqlfiddle.com/#!10/e70d9/4
I don't have anything as ancient as 8.0, 8.1 or 8.2 around but it should work on those pre-historic versions as well.
Note that offset is a reserved word in Postgres. You should find a different name for that column
In Oracle, to answer the specific question (i.e. a table with just the one row):
select rn posn from (
select offset-1+rownum rn from the_table
connect by level between offset and qty
);
In reality, your table will have multiple rows, so you will need to restrict the inner query to 1 object row, otherwise I think you will get huge, incorrect output. If you can provide more details about the table/data a more complete answer could be given.