Return dynamic columns by joining results of a stored function - sql

I have a stored function called Fnc_MyFunc(#myDate). it takes a date parameter and return a table like this:
user_id | count_laps
--------+-----------
1 | 85
2 | 37
5 | 55
12 | 48
i want to execute this for many dates (date interval).
with my function i whant a result like this: (laps per day for all users)
user_id | [2015-10-01] | [2015-10-02] | [2015-10-03] | ....
--------+--------------+--------------+--------------+--------------
1 | 85 | 2 | 66 | ....
2 | 37 | 58 | 85 | ....
5 | 55 | 33 | 75 | ....
12 | 48 | 44 | 55 | ....

This query should do what you want:
SELECT
u.userId,
d1.count_laps as [2015-10-01]
d2.count_laps as [2015-10-02],
d3.count_laps as [2015-10-03]
FROM
TableOrQueryWithDistinctUserIds u
LEFT JOIN Fnc_MyFunc('2015-10-01') d1 ON u.userId = d1.userId
LEFT JOIN Fnc_MyFunc('2015-10-02') d2 ON u.userId = d2.userId
LEFT JOIN Fnc_MyFunc('2015-10-03') d3 ON u.userId = d2.userId
You can then make it dynamic if necessary.

Related

How to count how many times a specific value appeared on each columns and group by range

I'm new on postgres and I have a question:
I have a table with 100 columns. I need to count the values from each columns and count how many times they appeared, so I can group then based on the range that they fit
I have a table like this(100 columns)
+------+------+------+------+------+---------+--------+
| Name | PRB0 | PRB1 | PRB2 | PRB3 | ....... | PRB100 |
+------+------+------+------+------+---------+--------+
| A | 15 | 6 | 47 | 54 | ..... | 8 |
| B | 25 | 22 | 84 | 86 | ..... | 76 |
| C | 57 | 57 | 96 | 38 | ..... | 28 |
+------+------+------+------+------+---------+--------+
And need the output to be something like this
+------+---------------+----------------+----------------+----------------+-----+-----------------+--+
| Name | Count 0 to 20 | Count 21 to 40 | Count 41 to 60 | Count 61 to 70 | ... | Count 81 to 100 | |
+------+---------------+----------------+----------------+----------------+-----+-----------------+--+
| A | 5 | 46 | 87 | 34 | ... | 98 | |
| B | 5 | 2 | 34 | 56 | ... | 36 | |
| C | 7 | 17 | 56 | 78 | ... | 88 | |
+------+---------------+----------------+----------------+----------------+-----+-----------------+--+
For Name A we have:
5 times the number between 0 and 20 apeared
46 times the number between 21 and 40 appeared
86 times the number between 41 and 60 appeared
Basicaly I need something like the function COUNTIFS that we have on Excel. On excel we just need to especify the range of columns and the condition.
You could unpivot with a lateral join, then aggregate:
select
name,
count(*) filter(where prb between 0 and 20) cnt_00_20,
count(*) filter(where prb between 21 and 50) cnt_21_20,
...,
count(*) filter(where prb between 81 and 100) cnt_81_100
from mytable t
cross join lateral (values(t.prb0), (t.prb1), ..., (t.prb100)) p(prb)
group by name
Note, however, that this still requires you to enumerate all the columns in the values() table constructor. If you want something fully dynamic, you can use json instead. The idea is to turn each record to a json object using to_jsonb(), then to rows with jsonb_each(); you can then do conditional aggregation.
select
name,
count(*) filter(where prb::int between 0 and 20) cnt_00_20,
count(*) filter(where prb::int between 21 and 50) cnt_21_20,
...,
count(*) filter(where prb::int between 81 and 100) cnt_81_100
from mytable t
cross join lateral to_jsonb(t) j(js)
cross join lateral jsonb_each( j.js - 'name') r(col, prb)
group by name

Join Two Tables Where Difference Between Unique Identifier Key Is 1

I need to join two tables where the unique identifying key is a difference of 1. Take for instance table A and B below:
Table A
+-----+-------+--------+
| Key | Check | Amount |
+-----+-------+--------+
| 23 | 3 | $600 |
| 46 | 72 | $2043 |
| 67 | 4 | $99 |
| 85 | 16 | $1 |
+-----+-------+--------+
Table B
+-----+-------+------+
| Key | Seq | Flag |
+-----+-------+------+
| 24 | 546 | Y |
| 47 | 254 | Y |
| 68 | 687 | N |
| 86 | 3475 | Y |
+-----+-------+------+
The Key column should join both tables together, but are separated by a difference of 1 value. In table A, Key 23 should join on Table B's Key 24. So, 23 + 1 = 24. For Table A 46, the Key in B is 47 so 46 + 1 = 47 etc.
Any ideas on how to get around this?
Try use a proper ON clause for join
select A.*, B.*
FROM TableA A
INNER JOIN TableB B On A.key +1 = B.key
This is the correct solution;
SELECT A.*, B.*
FROM TableA A
INNER JOIN TableB B On A.key = B.key - 1;

Query to get the count of data for particular customer with all other data from table

My table structure is as follows:
group_id | cust_id | ticket_num
------------------------------
60 | 12 | 1
60 | 12 | 2
60 | 12 | 3
60 | 12 | 4
60 | 30 | 5
60 | 30 | 6
60 | 31 | 7
60 | 31 | 8
65 | 02 | 1
I want to fetch all the data for group_id=60 and find the count of ticket_num for each customer in that group. My output should be like this:
cust_id | ticket_count | ticket_num
------------------------------
12 | 4 | 1
12 | | 2
12 | | 3
12 | | 4
30 | 2 | 5
30 | | 6
31 | 2 | 7
31 | | 8
I tried this query:
SELECT gd.cust_id, Count(gd.cust_id),gd.ticket_num
FROM Group_details gd
WHERE gd.group_id = 65
GROUP BY gd.cust_id;
But this query is not working.
You appear to want the ANSI/ISO standard row_number() functions and count() as a window function:
select gd.cust_id, count(*) over (partition by gd.cust_id) as num_tickets,
row_number() over (order by gd.cust_id) as ticket_seqnum
from group_details gd
where gd.group_id = 60;
use aggregate and subquery
select t2.*,t1.ticket_num from Group_details t1
inner join
(
SELECT gd.cust_id, Count(gd.ticket_num) as ticket_count
FROM Group_details gd where gd.group_id = 60
GROUP BY gd.cust_id
) t2 on t1.cust_id=t2.cust_id
http://sqlfiddle.com/#!9/dd718b/1

SQL, Update with most recent data info

I have 2 tables shown below:
Table 1
Student ID - DATE_NO - SCORE
Table 2
STUDENT_ID - DATE_NO - HT - WT
Table 1 has the physical test scores and the date of the test for each student while Table 2 lists their height (HT) and weight (WT) and the date they were measured.
Example Data:
Table 1
Student ID | DATE_NO | SCORE |
125 | 3 | 90 |
572 | 6 | 75 |
687 | 11 | 95 |
Table 2
Student_ID | DATE_NO | HT | WT |
125 | 2 | 70 | 150 |
125 | 3 | 72 | 155 |
125 | 6 | 72 | 160 |
572 | 2 | 70 | 200 |
572 | 5 | 70 | 225 |
572 | 8 | 70 | 215 |
572 | 9 | 70 | 220 |
687 | 4 | 65 | 140 |
687 | 7 | 67 | 150 |
687 | 11 | 70 | 155 |
687 | 12 | 67 | 160 |
I am not guaranteed to have the exact same DATE_NO for both HT/WT and the Test score date. I want the most recent HT and WT for each student when they took their physical test. Based on the example data above, the optimal join would give me the table below:
Modified Table 1
Student ID | DATE_NO | HT | WT |
125 | 3 | 72 | 155 |
572 | 6 | 70 | 225 |
687 | 11 | 70 | 155 |
I'd like to use the UPDATE statement on Table 1, so after altering Table 1 with HT int and WT int, I attempt to do the following:
UPDATE T1
SET HT = T2.HT, WT = T2.WT
FROM Table_1 as T1
INNER JOIN Table_2 AS T2 ON T1.STUDENT_ID = T2.STUDENT_ID
WHERE (T1.DATE_NO) >= (T2.DATE_NO)
But the result gives me the FIRST record that meets the criteria. Switching greater than to less than [ >= to <= ] Make the HT/WT for each student the entries for Month 6,8, and 12) when it should be month 3,8, and 11. Any suggestions?
FYI: Won't be able to apply any solutions till Friday.
Is it something like this you're looking for:
UPDATE Q
SET
T1_HT = T2_HT
, T1_WT = T2_WT
FROM
(
SELECT
T1.HT T1_HT
, T1.WT T1_WT
, T2.HT T2_HT
, T2.WT T2_WT
, ROW_NUMBER() OVER (PARTITION BY T1.STUDENT_ID ORDER BY T2.DATE_NO DESC) R
FROM
Table_1 T1
JOIN Table_2 T2 ON
T1.STUDENT_ID = T2.STUDENT_ID
AND T2.DATE_NO <= T1.DATE_NO
) Q
WHERE R = 1
SELECT ts.student_id,
ts.date_no,
hw.ht,
hw.wt
FROM test_scores ts,
ht_wt hw
WHERE hw.student_id = ts.student_id
AND hw.date_no <= ts.date_no
AND hw.date_no =
(SELECT max(date_no)
FROM ht_wt
WHERE date_no <= ts.date_no
AND student_id = ts.student_id)
sql fiddle here

show duplicate rows in access

i have this table
MEN
id | Qty | Place
========================
111 | 10 | 55
111 | 20 | 66
111 | 10 | 77
222 | 40 | 11
333 | 50 | 11
111 | 10 | 22
222 | 44 | 33
222 | 40 | 44
333 | 15 | 55
i need to show all the records that id=id and Qty=Qty like this:
id | Qty | Place
=====================
111 | 10 | 55
111 | 10 | 77
111 | 10 | 22
222 | 40 | 11
222 | 40 | 44
You can do something like this:
SELECT MEN.Id, MEN.Qty, MEN.Place
FROM MEN INNER JOIN
(SELECT MEN.Id, MEN.Qty
FROM MEN
GROUP BY MEN.Id, MEN.Qty
HAVING (((Count(*))>1))) AS a
ON (MEN.Qty = a.Qty) AND (MEN.Id = a.Id)
ORDER BY MEN.Id, MEN.Qty;
Create the inner query to find where there are more than one instances of the Id then join it back to the original table to get the Place values.
Try this
SELECT T.ID,T.Qty
FROM Table1 T
GROUP BY T.ID,T.Qty
HAVING (((Count(*))>1));
Use Below query to get full set of record details:
SELECT R.Id, R.Qty, R.Place
FROM Table1 R INNER JOIN
(
SELECT T.Id, T.Qty
FROM Table1 T
GROUP BY T.Id, T.Qty
HAVING (((Count(*))>1))
)AS JR ON R.Qty = JR.Qty AND R.Id = JR.Id