I have a number of locations with people that are at various steps in a step-wise process. I'd like to be able to report the count of people at each step by location and then the total for all locations. So my data looks like this (steps table)
| ID | STEP_NUM | LOCATION ID |
-------------------------------
| 1 | 1 | 10 |
| 2 | 1 | 12 |
| 3 | 2 | 4 |
| 4 | 1 | 5 |
| 5 | 1 | 6 |
| 6 | 1 | 3 |
| 7 | 3 | 3 |
This stackoverflow question and answer(s) Postgresql Multiple counts for one table was very useful and I got the summary by location. Here is my current query:
SELECT locations.name,
sum(case when step_num = 1 then 1 end) as Beginner,
sum(case when step_num = 2 then 1 end) as Intermediate,
sum(case when step_num = 3 then 1 end) as Expert
FROM steps
INNER JOIN locations ON steps.location_id = locations.id
GROUP BY locations.name
ORDER BY locations.name ASC
How would I also return the total for all locations? For example I would like to get the result:
| LOCATION NAME | Beginner | Intermediate | Expert |
----------------------------------------------------
| Uptown | 5 | | 1 |
| Downtown | 2 | 1 | 3 |
| All locations | 7 | 1 | 4 |
You need rollup operation which is not supported in PostgreSQL yet but can be emulated
WITH location AS (
SELECT locations.name,
sum(case when step_num = 1 then 1 end) as Beginner,
sum(case when step_num = 2 then 1 end) as Intermediate,
sum(case when step_num = 3 then 1 end) as Expert
FROM steps
INNER JOIN locations ON steps.location_id = locations.id
GROUP BY locations.name
ORDER BY locations.name ASC
), total AS (
SELECT 'Total',
sum(Beginner),
sum(Intermediate),
sum(Expert)
FROM location
) SELECT *
FROM location
UNION ALL
SELECT *
FROM total
Related
I have two tables x and y. I want to join on column b such that I get z in output.
x:([a:1 2 1 3]; b:`a`a`b`b)
q) a | b
-----
1 | a
2 | a
1 | b
3 | b
y:([b:`a`a`a`b]; c:7 8 9 10)
q) b | c
------
a | 7
a | 8
a | 9
b | 10
Desired output:
q) a | b | c
-----------
1 | a | 7
1 | a | 8
1 | a | 9
2 | a | 7
2 | a | 8
2 | a | 9
1 | b | 10
3 | b | 10
Is this some sort of cross join?
An equi join (ej) will produce the result you want:
q)ej[`b;x;y]
I have a model Teststep with these columns and values:
+----------+----------+---------------+----------+
| name | sequence | inner_sequnce | revision |
+----------+----------+---------------+----------+
| Step A | 1 | 1 | 1 |
| Step B | 1 | 2 | 1 |
| Step B-2 | 1 | 2 | 2 |
| Step C | 1 | 3 | 1 |
| Step D | 2 | 1 | 1 |
+----------+----------+---------------+----------+
Now I want all teststeps with sequence 1 but only with the highest revision. So in this case it would include Step A, Step B-2 and Step C.
The query to get the teststeps with the right sequence is easy:
Teststep.where(sequence: 1)
But how can I make sure only Step B-2 is returned and not Step B or both Step B-2 and Step B?
You want to create a subquery and use an aggregate:
SELECT * FROM teststeps
WHERE
teststeps.sequence = 1
AND
teststeps.revision = (SELECT MAX(teststeps.revision) WHERE teststeps.sequence = 1)
The bad news is that the exact details of how to do this varies depending on which RDBMS is used.
In Rails you could do something like:
Teststep.where(sequence: 1)
.where(revision: Teststep.where(sequence: 1).maximum(:revision))
Hey folks: I have the following table in a vertica DB:
+-----+------+----------+
| Tid | item | time_sec |
+-----+------+----------+
| 1 | A | 1 |
| 1 | B | 2 |
| 1 | C | 4 |
| 1 | D | 5 |
| 1 | E | 6 |
| 2 | A | 5 |
| 2 | E | 5 |
+-----+------+----------+
My goal is to create new item groups that lie within a time window deltaT. Meaning that the difference between the first and last item's timestamp is smaller or equal to deltaT. Example: if deltaT = 2 sec we would get the new table:
+-----+------+
| Tid | item |
+-----+------+
| 11 | A |
| 11 | B |
| 12 | B |
| 12 | C |
| 13 | C |
| 13 | D |
| 13 | E |
| 14 | D |
| 14 | E |
| 15 | E |
| 21 | A |
| 21 | E |
+-----+------+
Here is the walk through of the table:
First we inspect all items with the Tid 1, and create sub groups with Tid 1n, where n is a counter.
Our first sub group with the Tid 11 consists of item A, B since deltaT between the last and first item is =<2. The next group has Tid 12 with item B,C. The group after that one has the Tid 13 and items C,D,E since all items are within a time span of 2 seconds. This goes on until the last item with Tid 1. Than we start over with the group that has Tid 2.
The new Tid numbering for the sub groups can be continous (1...6), I just choose this kind of numbering to show the relation to the original table.
I am looking at the vertica functions LAG and Time_slice but cannot figure out a way how to handle such a problem elegantly.
This is how far I got - and it does not answer your question, really. But it could constitute a few pointers:
WITH
-- your input
input(Tid,item,time_sec) AS (
SELECT 1,'A',1
UNION ALL SELECT 1,'B',2
UNION ALL SELECT 1,'C',4
UNION ALL SELECT 1,'D',5
UNION ALL SELECT 1,'E',6
UNION ALL SELECT 2,'A',5
UNION ALL SELECT 2,'E',5
)
-- end of your input, start your "real" WITH clause here
,
input_w_ts AS (
SELECT
*
, TIMESTAMPADD('SECOND',time_sec-1,TIMESTAMP '2000-01-01 00:00:00') AS ts
FROM input
)
SELECT
TS_LAST_VALUE(Tid) AS Tid
, item
, TS_LAST_VALUE(time_sec) AS time_sec
, tsr
FROM input_w_ts
TIMESERIES tsr AS '2 SECONDS' OVER (PARTITION BY item ORDER BY ts)
ORDER BY 1,4
;
Output:
Tid|item|time_sec|tsr
1|A | 1|2000-01-01 00:00:00
1|B | 2|2000-01-01 00:00:00
1|A | 1|2000-01-01 00:00:02
1|C | 4|2000-01-01 00:00:02
1|D | 5|2000-01-01 00:00:04
1|E | 6|2000-01-01 00:00:04
2|A | 5|2000-01-01 00:00:04
I have three tables
Personal_video
+------------------------------+
|presonal_video_id | title |
----------------------------
1 | test1|
2 | test2|
3 | test3|
4 | test4|
personal_video_tags
+------------------------------+
|tag_id | tag_title |
----------------------------
1 | august|
2 | 2016 |
3 | 2015 |
4 | 2014 |
personal_video_tag_mapping
+------------------------------+
|tag_id | presonal_video_id |
----------------------------
1 | 1 |
2 | 2 |
3 | 3 |
4 | 1 |
Now i want to write a query which will return me the videos on the basis of common tags like if user select tag "August" & "2014" then the query should return videos which is connected to both the tags.
currently my query is
SELECT presonal_video_id,title
FROM personal_video
WHERE presonal_video_id IN
(
SELECT personal_video_id AS PID
FROM personal_video_tag_mapping
WHERE tag_id IN ("1","2") AND privacy_level != 2
GROUP BY personal_video_id
HAVING COUNT( PID ) > 1
)
It is giving me write result but when there is large data then it takes long time. Can someone teel me correct way to write this query
Thank You in advance
Try this query:
SELECT t1.presonal_video_id, t1.title
FROM personal_video AS t1
JOIN personal_video_tag_mapping AS t2
ON t1.presonal_video_id = t2.presonal_video_id
JOIN personal_video_tags AS t3
ON t2.tag_id = t3.tag_id
WHERE t3.tag_title IN ('august', '2014')
GROUP BY t1.presonal_video_id, t1.title
HAVING COUNT(*) = 2
Im trying to find an efficient way to solve the problem:
I need to find all rows in a table where there is another row with an opposite column value.
For example I have transactions with columns id and amount
| id | amount |
|----|--------|
| 1 | 1 |
| 2 | -1 |
| 3 | 2 |
| 4 | -2 |
| 5 | 3 |
| 6 | 4 |
| 7 | 5 |
| 8 | 6 |
The query should return only the first 4 rows:
| id | amount |
|----|--------|
| 1 | 1 |
| 2 | -1 |
| 3 | 2 |
| 4 | -2 |
My current solution is terribly efficient as I am going through 1000's of transactions:
transactions.find_each do |transaction|
unless transactions.where("amount = #{transaction.amount * -1}").count > 0
transactions = transactions.where.not(amount: transaction.amount).order("# amount DESC")
end
end
transactions
Are there any built in Rails or Postgresql functions that could help with this?
Use following query:
SELECT DISTINCT t1.*
FROM transactions t1
INNER JOIN transactions t2 ON t1.amount = t2.amount * -1;
SELECT * FROM the_table t
WHERE EXISTS (
SELECT * FROM the_table x
WHERE x.amount = -1*t.amount
-- AND x.amount > t.amount
);
Consider storing an absolute value indexed column then query for the positive value. Postgres has an absolute value function; but I think the beauty of ActiveRecord is that Arel abstracts away the SQL. DB specific SQL can be a pain if you change later.
There is type called abs which will return irrespective of symobol. From my example data is the table name
SELECT id,amount FROM DATA WHERE id = ABS(amount)
This is the sample test table
Here is the output