I have data on table test like this
customer_no | name | chance
---------------------------
00000000001 | AAAA | 3
00000000002 | BBBB | 2
00000000003 | CCCC | 1
Now,i want to select from table test with multiple output that calculate by value of field chance
output like this
customer_no | name
------------------
00000000001 | AAAA
00000000001 | AAAA
00000000001 | AAAA
00000000002 | BBBB
00000000002 | BBBB
00000000003 | CCCC
how to select command in pgsql database?
Try this:
SELECT customer_no, name FROM (
SELECT test.*,
generate_series(1,chance) i
FROM test
) test;
Here is a demo.
with recursive CTE_nums as (
select max(chance) as num from test
union all
select num - 1 from CTE_nums
where num > 1
)
select
t.customer_no, t.name
from test as t
inner join CTE_nums as n on n.num <= t.chance
order by 1, 2
SQL FIDDLE EXAMPLE
Related
Suppose I have users stored as
select * from users_t where user_name like 'ABC%';
id user_name
1 ABC1
2 ABC2
.. ..
Now I need to loop through all user_name's and make that number of INSERTs into a different table, RECALLS_T. All the other columns are hard-coded constants that I define.
Assume the following table, with a Sequence called RECALLS_T_ID_SEQ on the ID:
id created_by_user_name field1 field2
1 ABC1 Const1 Const2
2 ABC2 Const1 Const2
.. .. .. ..
How do I insert these in a Postgres loop?
ADDITIONAL QUESTION Also, what if I need to insert X (say 5) Recalls for each User entry? Suppose it's not a 1:1 mapping, but 5:1, where 5 is a hard-coded loop number.
You can use the select in the insert statement:
insert into recalls_t (created_by_user_name, field1, field2)
select user_name, 'Const1', 'Const2'
from users_t
where user_name like 'ABC%';
Use the function generate_series() to insert more than one row for each entry from users_t. I have added the column step to illustrate this:
insert into recalls_t (created_by_user_name, field1, field2, step)
select user_name, 'Const1', 'Const2', step
from users_t
cross join generate_series(1, 3) as step
where user_name like 'ABC%'
returning *
id | created_by_user_name | field1 | field2 | step
----+----------------------+--------+--------+------
1 | ABC1 | Const1 | Const2 | 1
2 | ABC2 | Const1 | Const2 | 1
3 | ABC1 | Const1 | Const2 | 2
4 | ABC2 | Const1 | Const2 | 2
5 | ABC1 | Const1 | Const2 | 3
6 | ABC2 | Const1 | Const2 | 3
(6 rows)
Live demo in Db<>fiddle.
As the title says, I need to create a query where I SELECT all items from one table and use those items as expressions in another query. Suppose I have the main table that looks like this:
main_table
-------------------------------------
id | name | location | //more columns
---|------|----------|---------------
1 | me | pluto | //
2 | them | mercury | //
3 | we | jupiter | //
And the sub query table looks like this:
some_table
---------------
id | item
---|-----------
1 | sub-col-1
2 | sub-col-2
3 | sub-col-3
where each item in some_table has a price which is in an amount_table like so:
amount_table
--------------
1 | 1000
2 | 2000
3 | 3000
So that the query returns results like this:
name | location | sub-col-1 | sub-col-2 | sub-col-3 |
----------------------------------------------------|
me | pluto | 1000 | | |
them | mercury | | 2000 | |
we | jupiter | | | 3000 |
My query currently looks like this
SELECT name, location, (SELECT item FROM some_table)
FROM main_table
INNER JOIN amount_table WHERE //match the id's
But I'm running into the error more than one row returned by a subquery used as an expression
How can I formulate this query to return the desired results?
you should decide on expected result.
to get one-tp-many relation:
SELECT name, location, some_table.item
FROM main_table
JOIN some_table on true -- or id if they match
INNER JOIN amount_table --WHERE match the id's
to get one-to-one with all rows:
SELECT name, location, (SELECT array_agg(item) FROM some_table)
FROM main_table
INNER JOIN amount_table --WHERE //match the id's
I'm using Postgresql. Let's say I have 3 tables:
Classes
id | name
1 | Biology
2 | Math
Students
id | name
1 | John
2 | Jane
Student_Classes
id | student_id | class_id | registration_token
1 | 1 | 1 | abc
2 | 1 | 2 | def
3 | 2 | 1 | zxc
I want to obtain a result set like this:
Results
student_name | biology | math
John | abc | def
Jane | zxc | NULL
I can get this result set with this query:
SELECT
student.name as student_name,
biology.registration_token as biology,
math.registration_token as math
FROM
Students
LEFT JOIN (
SELECT registration_token FROM Student_Classes WHERE class_id = (
SELECT id FROM Classes WHERE name = 'Biology'
)
) AS biology
ON Students.id = biology.student_id
LEFT JOIN (
SELECT registration_token FROM Student_Classes WHERE class_id = (
SELECT id FROM Classes WHERE name = 'Math'
)
) AS math
ON Students.id = math.student_id
Is there a way to get this same result set without having a join statement for each class? With this solution, if I want to add a class, I need to add another join statement.
You can do this via postgresql tablefunc extension crosstab but such presentation requirements may be handled better outside of sql.
Let me draw up the table first (there are dozens of columns and dozens of values under Code in reality)
Code | Pat | Col1 | Col2 | Col3
---------------------------------
ABC | 001 | | XX | Q1
ABC | 002 | xx | xx | Q1
ABC | 003 | xx | xxx | Q1
DEF | 004 | xx | xx | Q1
DEF | 005 | xx | xx | Q1
DEF | 006 | xx | xxx | Q1
The resulting table need to look like
ABC | DEF
---------
2 | 3
3 | 3
Let me try and explain. For each 'Code' column, I would need to count the number of entries in Col1 to ColX where the cell is not null/empty.
So in example above, Code ABC has a count of 2 in Col1 and a count of 3 in Col2 Similarly for DEF, both have a count of 3
I've tried lots of things but got to the point where I'm now looking at a blank page again!
ALTERNATIVELY
Code | Col1 | Col2
--------------------
ABC | 2 | 3
DEF | 3 | 3
Please advise
The alternative solution can be reached by using GROUP BY and summing up a calculated number:
SELECT
[Code],
SUM(CASE WHEN ISNULL(Col1, '') = '' THEN 0 ELSE 1 END) as [Col1],
SUM(CASE WHEN ISNULL(Col2, '') = '' THEN 0 ELSE 1 END) as [Col2],
...
FROM T
GROUP by [Code]
I have a table which has two columns C1 and C2.
C1 has an integer data type and C2 has text.
Table looks like this.
---C1--- ---C2---
1 | a |
1 | b |
1 | c |
1 | d |
1 | e |
1 | f |
1 | g |
2 | h |
2 | i |
2 | j |
2 | k |
2 | l |
2 | m |
2 | n |
------------------
My question: i want a sql query which does group by on column C1 but with size of 3.
looks like this.
------------------
1 | a,b,c |
1 | d,e,f |
1 | g |
2 | h,i,j |
2 | k,l,m |
2 | n |
------------------
is it possible by executing SQL???
Note: I do not want to write stored procedure or function...
You can use a common table expression to partition the results into rows, and then use STRING_AGG to join them into comma separated lists;
WITH cte AS (
SELECT *, (ROW_NUMBER() OVER (PARTITION BY C1 ORDER BY C2)-1)/3 rn
FROM mytable
)
SELECT C1, STRING_AGG(C2, ',') ALL_C2
FROM cte
GROUP BY C1,rn
ORDER BY C1
An SQLfiddle to test with.
A short explanation of the common table expression;
ROW_NUMBER() OVER (...) will number the results from 1 to n for each value of C1. We then subtract 1 and divide by 3 to get the sequence 0,0,0,1,1,1,2,2,2... and group by that value in the outer query to get 3 results per row.
Apart from Joachim Isaksson's answer,you try this method also
SELECT C1, string_agg(C2, ',') as c2
FROM (
SELECT *, (ROW_NUMBER() OVER (PARTITION BY C1 ORDER BY C2)-1)/3 as row_num
FROM atable) t
GROUP BY C1,row_num
ORDER BY c2