I have this code that gives me a list of where user can go:
SELECT place_name,user_id,user_name
FROM code.place, code.user
WHERE (place.place_id, user_id) NOT IN(
SELECT place_id, user_id
FROM code.visit
WHERE visit.user_id BETWEEN 1 AND 15
AND age(date) <= interval '4 months'
)
AND user_id BETWEEN 1 AND 15
I want to know if it would be possible to make a code that could take this list and define the following:
Select 2 places to user with id=1
Select 1 places to user with id=2
Select 3 places to user with id=3
Based on the list above, of course (AND without repeated places, as the list above gives repeated places). The result should look like this.
place_name|user_id|user_name|
COSCO |1 | james |
WALMART |1 | james |
MALL |2 | carlos |
TARGET |3 | jane |
7ELEVEN |3 | jane |
NESTLE |3 | jane |
I am sorry if it's a silly question but I am new to PostegreSQL (any SQL at all) and need to know the limitations of this language to do a project that I have (I am a intern).
The code "SELECT" gives me the "table" below. The first "table" is what I need to create.
place_name|user_id|user_name|
1 NESTLE |1 | james |
2 7ELEVEN |1 | james |
3 MALL |1 | james |
4 TARGET |1 | james |
5 COSCO |2 | carlos |
6 WALMART |2 | carlos |
7 TARGET |2 | carlos |
8 7ELEVEN |2 | carlos |
9 NESTLE |2 | carlos |
10 COSCO |3 | jane |
11 WALMART |3 | jane |
12 MALL |3 | jane |
The CREATE TABLE code looks like this:
CREATE TABLE code.place (
place_id VARCHAR(8),
place_name VARCHAR (50),
CONSTRAINT pk_place_id PRIMARY KEY (place_id)
);
CREATE TABLE code.user (
user_id VARCHAR(3),
user_name VARCHAR (50),
CONSTRAINT pk_user_id PRIMARY KEY (user_id)
);
CREATE TABLE code.visit (
user_id VARCHAR(3),
place_id VARCHAR(8),
date DATE,
CONSTRAINT pk_user_id FOREIGN KEY (user_id) REFERENCES SCHEMA.user,
CONSTRAINT pk_place_id FOREIGN KEY (place_id) REFERENCES code.place,
EXCLUDE USING gist (pk_user_id WITH =, daterange(data, (data + interval '6 months')::date) WITH &&)
);
Related
I need somehow to group my rows by specific condition
|id | address | last_name | Count of purchases | customer_number |
|1 | de Berlin | name_1 | 1 | 11111 |
|2 | de Berlin | name_2 | 1 | 12345 |
|3 | de Berlin | name_1 | 1 | 12345 |
So the problem is that I need to group by address AND last_name BUT in this case row with ID = 2 will not be in set because it has different last_name BUT it shares the same customer_number number with row with ID = 3. Can I do it somehow with one query?
So basically I want to receive something like
select SUM(Count_of_purchases), array_agg(last_name), array_agg(customer_number)
from table
group by f(address, last_name, customer_number)
| 3 | {name_1, name_2} | {11111, 12345} |
I have a table visits that shows the navigation of a user in a website. The ultimate goal is to have an estimation of the time a user spent in each area of the website.
| user_id | timestamp | area_visited | visit_it |
| ------- | ------------------------- | ------------- | -------------- |
| 1 | 2021-03-02 19:34:09.708+00| area1 |1 |
| 1 | 2021-03-02 19:34:16.53+00 | area2 |2 |
| 1 | 2021-03-02 19:34:18.697+00| area2 |2 |
| 1 | 2021-03-02 19:34:56.367+00| area1 |3 |
| 2 | 2021-03-02 19:35:16.53+00 | area1 |1 |
| 2 | 2021-03-02 19:36:52.53+00 | area3 |2 |
| 2 | 2021-03-02 19:38:16.53+00 | area3 |3 |
I tried to use dense_rank but the results is not exactly what I need. I want to increment the visit_id field only when the user visits a new area in the website. If the user visits an area, then another one and comes back to the first, I still want that to be considered as a different visit_id
I tried the following query but it does not take the chronological order of the visits
select *, dense_rank() over (order by user_id,area) as visit_id from visits
Then this, but that does not work as each timestamp is unique
select *, dense_rank() over (order by user_id,timestamp, area) as visit_id from visits
Any idea how to do this?
Thanks!
I think you are looking for this :
select *
, dense_rank() over (partition by user_id order by timestamp)
- dense_rank() over (partition by user_id,area_visited order by timestamp) as visit_id
from visits
I have three tables lets say table_a, table_b, table_c whose structure are as follows,
table_a,
id | name | created_at | updated_at
---------------------------------------------------------------
1 |john doe |2021-01-01 15:00:00 |2021-01-01 15:00:00
table_b,
id | package | created_at | updated_at
---------------------------------------------------------------
1 |package_1 |2021-01-01 15:01:00 |2021-01-01 15:0:00
table_c,
id | table_a_id | packages | created_at | updated_at
--------------------------------------------------------------------------------------------------------
1 |1 |[{"id":1, "package": "package_1"}] |2021-01-01 15:10:00 |2021-01-01 15:10:00
I need to run a query and get the count of packages based on users. For example, the result should be as follows,
table_a_id | table_a_name | table_b_id | table_b_package | total_count
--------------------------------------------------------------------------------------------------------
1 |john doe |1 |package_1 |2
There can be multiple package in packages column of table_b as [{...}]
How can i achieve the result.
If you just need to count the number of elements in your table_c.packages, then you can use jsonb_array_length -
Final Query would look like -
select
a.id,a.name,jsonb_array_length(c.packages) as count
from table_a a
join table_c c on a.id = c.table_a_id
I am not sure what role table_b plays here so I have skipped it.
I have a sample table named antest as shown below to test the crosstab function.
create table antest(student text, subject text, result numeric);
insert into antest(student, subject, result) values
('peter','music',2.0),
('peter','language',2.0),
('gabriel','history',8.0),
('john','history',9.0),
('john','maths',4.0),
('john','music',7.0);
student|subject|result
-------+-------+------
peter |music |2.0
peter |lanuage|2.0
gabriel|history|8.0
john |history|9.0
john |maths |4.0
john |music |7.0
Result wanted:
student|music|language|history|maths
-------+-----+--------+-------+-----
peter |2.0 |2.0 | |
gabriel| | |8.0 |
john |7.0 | |9.0 |4.0
I have executed the follwoin query for that:
select *
from public.crosstab (
'select student, subject, result from antest',
'select distinct subject from antest'
) as final_result(student text, music numeric, maths numeric, history numeric, language numeric);
I got the following result:
student|music|maths|history|language
-------+-----+-----+-------+--------
peter |2.0 | | |2.0
gabriel| |8.0 | |
john |7.0 |9.0 |4.0 |
Kindly let me know the mistake I am doing.
I have to repeat this query for anyother database which is 30gb large later with about 75 attributes. Is there any possibility to automate it?
You have to take care that the order of categories is exactly the same in the category query and in the column definition. Because you want an arbitrary chosen (not alphabetical) order, you should use values in the category query.
select *
from crosstab (
$q$ select student, subject, result from antest $q$,
$q$ values ('music'), ('language'), ('history'), ('maths') $q$
) as final_result(student text, music numeric, language numeric, history numeric, maths numeric);
student | music | language | history | maths
---------+-------+----------+---------+-------
peter | 2.0 | 2.0 | |
gabriel | | | 8.0 |
john | 7.0 | | 9.0 | 4.0
(3 rows)
Of course, you can use order by in the query but then you have to change the order in the column definition:
select *
from crosstab (
$q$ select student, subject, result from antest $q$,
$q$ select distinct subject from antest order by 1 $q$
) as final_result(student text, history numeric, language numeric, math numeric, music numeric);
student | history | language | math | music
---------+---------+----------+------+-------
peter | | 2.0 | | 2.0
gabriel | 8.0 | | |
john | 9.0 | | 4.0 | 7.0
(3 rows)
How I can sort a hierarchical table with CTE query ?
sample table :
|ID|Name |ParentID|
| 0| |-1 |
| 1|1 |0 |
| 2|2 |0 |
| 3|1-1 |1 |
| 4|1-2 |1 |
| 5|2-1 |2 |
| 6|2-2 |2 |
| 7|2-1-1 |5 |
and my favorite result is :
|ID|Name |ParentID|Level
| 0| |-1 |0
| 1|1 |0 |1
| 3|1-1 |1 |2
| 4|1-2 |1 |2
| 2|2 |0 |1
| 5|2-1 |2 |2
| 7|2-1-1 |5 |3
| 6|2-2 |2 |2
another Sample :
an other sample :
|ID|Name |ParentID|
| 0| |-1 |
| 1|Book |0 |
| 2|App |0 |
| 3|C# |1 |
| 4|VB.NET |1 |
| 5|Office |2 |
| 6|PhotoShop |2 |
| 7|Word |5 |
and my favorite result is :
|ID|Name |ParentID|Level
| 0| |-1 |0
| 1|Book |0 |1
| 3|C# |1 |2
| 4|VB.NET |1 |2
| 2|App |0 |1
| 5|Office |2 |2
| 7|Word |5 |3
| 6|PhotoShop |2 |2
The hierarchyid datatype is able to represent hierarchical data, and already has the desired sorting order. If you can't replace your ParentID column, then you can convert to it on the fly:
(Most of this script is data setup, the actual answer is quite small)
declare #t table (ID int not null,Name varchar(10) not null,ParentID int not null)
insert into #t(ID,Name,ParentID)
select 0,'' ,-1 union all
select 1,'Book' ,0 union all
select 2,'App' ,0 union all
select 3,'C#' ,1 union all
select 4,'VB.NET' ,1 union all
select 5,'Office' ,2 union all
select 6,'PhotoShop' ,2 union all
select 7,'Word' ,5
;With Sensible as (
select ID,Name,NULLIF(ParentID,-1) as ParentID
from #t
), Paths as (
select ID,CONVERT(hierarchyid,'/' + CONVERT(varchar(10),ID) + '/') as Pth
from Sensible where ParentID is null
union all
select s.ID,CONVERT(hierarchyid,p.Pth.ToString() + CONVERT(varchar(10),s.ID) + '/')
from Sensible s inner join Paths p on s.ParentID = p.ID
)
select
*
from
Sensible s
inner join
Paths p
on
s.ID = p.ID
order by p.Pth
ORDER BY Name should work as desired:
WITH CTE
AS(
SELECT parent.*, 0 AS Level
FROM #table parent
WHERE parent.ID = 0
UNION ALL
SELECT parent.*, Level+1
FROM #table parent
INNER JOIN CTE prev ON parent.ParentID = prev.ID
)
SELECT * FROM CTE
ORDER BY Name
Here's your sample data(add it next time yourself):
declare #table table(ID int,Name varchar(10),ParentID int);
insert into #table values(0,'',-1);
insert into #table values(1,'1',0);
insert into #table values(2,'2',0);
insert into #table values(3,'1-1',1);
insert into #table values(4,'1-2',1);
insert into #table values(5,'2-1',2);
insert into #table values(6,'2-2',2);
insert into #table values(7,'2-1-1',5);
Result:
ID Name ParentID Level
0 -1 0
1 1 0 1
3 1-1 1 2
4 1-2 1 2
2 2 0 1
5 2-1 2 2
7 2-1-1 5 3
6 2-2 2 2