Loop through a ColdFusion query and sorting results - coldfusion

I have two tables:
Users (2 columns): ID, DisplayName, Active
Ticket_Followups (4 colums): id, requested_by, requested_date, ticket_id
I am tryiwng to group all the similar records in the ticket_followup table, first by recordcount and then by displayName.
Here is what I have so far:
<cfquery name="active_users" datasource="#datasource#">
select * from users
where active='1'
</cfquery>
<cfloop query="active_users">
<cfquery name="get_followups" datasource="#datasource#">
select date_of_followup_request, requested_by, ticket_id
from ticket_followup
where requested_by = '#active_users.displayName#'
</cfquery>
<cfoutput>
<tr>
<td>#active_users.displayName#</td>
<td>#get_followups.recordcount#</td>
</tr>
</cfoutput>
</cfloop>
I am able to successfully show the output for the total records by user, but there is no order to the output. I would like to group it so that it shows the DisplayName with the highest recordcount first, descending in order.
How can I do that?

This is a SQL issue, CF is just displaying data after the data is gathered.
You need to do this in one query.
You need to associate the ticket follow ups by user ID, not by name (Name could change, but not the ID).
There's a table of tickets I assume, but we'll stick to your two tables.
First, the tables:
Users
----------
id
DisplayName
Active
Ticket_Followups
----------
id
requested_by_id (Users.id)
requested_date
ticket_id
You can technically join by name, but it's a much slower query and I've no idea how much data you have.
This query joins the two tables and gives you a count of ticket follow ups by user. You can add an ORDER BY statement before the GROUP BY depending on your needs.
SELECT
a.DisplayName
, count(*) AS requested_count
FROM
Users AS a
INNER JOIN
Ticket_Followups b ON b.requested_by_id = a.id
WHERE
a.active = 1
GROUP BY
a.id
If you don't do this in one query, then for every user that has an active ticket, you're making another query.
10 users, 11 queries
20 users, 21 queries
etc.
Updated 2022-02-15
Query using DisplayName with an ORDER BY clause. This should make it clearer that you're counting the tickets per user and not the number of users.
SELECT
a.DisplayName
, count(a.*) AS ticket_count
FROM
Ticket_Followups AS a
INNER JOIN
Users AS b ON b.DisplayName = a.DisplayName
WHERE
a.active = 1
ORDER BY
a.DisplayName DESC
GROUP BY
a.DisplayName
Output:
<cfoutput query="queryName">
<li>#queryName.DisplayName# - #queryName.ticket_count#</li>
</cfoutput>

Related

Compare a date in CFQUERY to current month

I am running a cfquery to pull records from a table:
<cfquery name="get_followups_monthly" datasource="#datasource#">
SELECT
a.DisplayName
, count(*) AS requested_count
FROM
users AS a
INNER JOIN
ticket_followup b ON b.requested_by = a.displayName
WHERE
a.active = 1 AND b.date_of_followup_request < '2022-02-01'
GROUP BY
a.DisplayName
ORDER BY requested_count DESC
</cfquery>
I would like to compare the dates returned in column b.date_of_followup_request to see if falls within the current month.
I looked through the builtin functions but don't see anything for that. How can this be accomplished?

Why bigquery can't handle a query processing 4TB data?

I'm trying to run this query
SELECT
id AS id,
ARRAY_AGG(DISTINCT users_ids) AS users_ids,
MAX(date) AS date
FROM
users,
UNNEST(users_ids) AS users_ids
WHERE
users_ids != " 1111"
AND users_ids != " 2222"
GROUP BY
id;
Where users table is splitted table with id column and user_ids (comma separated) column and date column
on a +4TB and it give me resources
Resources exceeded during query execution: Your project or organization exceeded the maximum disk and memory limit available for shuffle operations.
.. any idea why?
id userids date
1 2,3,4 1-10-20
2 4,5,6 1-10-20
1 7,8,4 2-10-20
so the final result I'm trying to reach
id userids date
1 2,3,4,7,8 2-10-20
2 4,5,6 1-10-20
Execution details:
It's constantly repartitioning - I would guess that you're trying to cramp too much stuff into the aggregation part. Just remove the aggregation part - I don't even think you have to cross join here.
Use a subquery instead of this cross join + aggregation combo.
Edit: just realized that you want to aggregate the arrays but with distinct values
WITH t AS (
SELECT
id AS id,
ARRAY_CONCAT_AGG(ARRAY(SELECT DISTINCT uids FROM UNNEST(user_ids) as uids WHERE
uids != " 1111" AND uids != " 2222")) AS users_ids,
MAX(date) OVER (partition by id) AS date
FROM
users
GROUP BY id
)
SELECT
id,
ARRAY(SELECT DISTINCT * FROM UNNEST(user_ids)) as user_ids
,date
FROM t
Just the draft I assume id is unique but it should be something along those lines? Grouping by arrays is not possible ...
array_concat_agg() has no distinct so it comes in a second step.

Amazon Athena LEFT OUTER JOIN query not working as expected

I am trying to do a left ourter join in Athena and my query looks like the following:
SELECT customer.name, orders.price
FROM customer LEFT OUTER JOIN order
ON customer.id = orders.customer_id
WHERE price IS NULL;
Where each customer could only have one order in the orders table at most and there are customers with no order in the orders table at all. So I am expecting to get some number of records where there is a customer in the customer table with no records in orders table which means when I do LEFT OUTER JOIN the price will be NULL. But this query returns 0 every time I run it. I have queries both tables separately and pretty sure there is data in both but not sure why this is returning zero where it works if I remove the price IS NULL. I have also tried price = '' and price IN ('') and none of them works. Has anyone here had a similar experience before? Or is there something wrong with my query that I can not see or identify?
It seems that your query is correct. To validate, I created two CTEs that should match up with your customer and orders table and ran your query against them. When running the query below, it returns a record for customer 3 Ted Johnson who did not have an order.
WITH customer AS (
SELECT 1 AS id, 'John Doe' AS name
UNION
SELECT 2 AS id, 'Jane Smith' AS name
UNION
SELECT 3 AS id, 'Ted Johnson' AS name
),
orders AS (
SELECT 1 AS customer_id, 20 AS price
UNION
SELECT 2 AS customer_id, 15 AS price
)
SELECT customer.name, orders.price
FROM customer LEFT OUTER JOIN orders
ON customer.id = orders.customer_id
WHERE price IS NULL;
I'd suggest running the following queries:
COUNT(DISTINCT id) FROM customers;
COUNT(DISTINCT customer_id) FROM orders;
Based on the results you are seeing, I would expect those counts to match. Perhaps your system is creating a record in the orders table whenever a customer is created with a price of 0.
Probably you can't use where for order table.
SELECT customer.name, order.price
FROM customer LEFT OUTER JOIN order
ON customer.id = orders.customer_id AND order.price IS NULL;

How to order a query by values in different columns

I have a recordset named rsProductClass that is returned from a table in the database. It is a very simple SELECT * FROM Table WHERE ProductID = {ID Value Here} and the table is like this:
ProductID | UPPERTIER | LOWERTIER | NATIER | OTHERTIER
1 20 60 10 10
2 10 90 NULL NULL
3 NULL 40 NULL 5
The table may or may not have a value for each of the various tiers.
What I want to do is show to the user which column has the highest value and what the name of that column is. So for example, if you were looking at ProductID 2, then the page should display "This is likely to be a LOWERTIER product"
I need to sort the rsProductClass query in such a way that it returns me a list of columns in that query ordered by the value in each column. I want to treat the NULL values as zeros.
I tried to mess about with doing valuelist() and some ArrayToList() type functions but it crashes on the NULL values. Say I add columns to an array, and then use ArraySort() to get them in some kind of order, I'll get an error saying something like "Position 1 is not numeric" because it has a NULL value.
Is this something that can be done by ColdFusion? I suppose its some sort of pivoting of the recordset which is beyond my ability.
Something like this would work:
<cfquery name="tiers" datasource="...">
SELECT ProductID, UPPERTIER VALUE, 'UPPERTIER' TIER
WHERE UPPERTIER IS NOT NULL
UNION
SELECT ProductID, LOWERTIER VALUE, 'LOWERTIER' TIER
WHERE LOWERTIER IS NOT NULL
UNION
SELECT ProductID, OTHERTIER VALUE, 'OTHERTIER' TIER
WHERE OTHERTIER IS NOT NULL
UNION
SELECT ProductID, NATIER VALUE, 'NATIER' TIER
WHERE NATIER IS NOT NULL
ORDER BY ProductID, VALUE
</cfquery>
<cfset productGroup = StructNew()>
<cfoutput query="tiers" group="ProductID">
<cfset productGroup[ProductID].TIER = TIER>
<cfset productGroup[ProductID].VALUE = VALUE>
</cfoutput>
<cfdump var="#productGroup#">
Starting with ColdFusion 10 you can use <cfloop query="..." group="...">, before that <cfoutput> must be used.
If you're willing to unpivot your query, you might do something like the following. I used COALESCE() instead of ISNULL() (either one works in this situation, but COALESCE() is the ANSI standard). The column tier_rank will give the rank of the given tier -- that is, the tier with the highest value will have a rank of 1. If there are two tiers that both have the highest value, then both will have a value in tier_rank of 1 (this is why you would use RANK() instead of ROW_NUMBER() -- you could also use DENSE_RANK() if it better fits your requirements):
SELECT p1.product_id, p1.tier_name, p1.tier_value
, RANK() OVER ( PARTITION BY p1.product_id ORDER BY p1.tier_value DESC ) tier_rank
FROM (
SELECT product_id, 'UPPERTIER' AS tier_name
, COALESCE(uppertier, 0) AS tier_value
FROM products
UNION ALL
SELECT product_id, 'LOWERTIER' AS tier_name
, COALESCE(lowertier, 0) AS tier_value
FROM products
UNION ALL
SELECT product_id, 'NATIER' AS tier_name
, COALESCE(natier, 0) AS tier_value
FROM products
UNION ALL
SELECT product_id, 'OTHERTIER' AS tier_name
, COALESCE(othertier, 0) AS tier_value
FROM products
) p1
Please see SQL Fiddle demo here.
It might be possible to re-pivot the above unpivoted query, but I must admit my attempts at doing so failed.
I had to do something similar to this recently and looked into UNPIVOT in SQL Server. Going with the suggestion to Unpivot your query like David said, you could do something like this. This doesn't add RANK column, but it does order the values.
SELECT ProductID, Tier, TierValue
FROM
(SELECT ProductID, ISNULL(UpperTier,0) UpperTier, ISNULL(LowerTier,0) LowerTier, ISNULL(NaTier,0) NaTier, ISNULL(OtherTier,0) OtherTier
FROM products) p
UNPIVOT
(TierValue FOR Tier IN
(UpperTier, LowerTier, NaTier, OtherTier)
)AS unpvt
ORDER BY ProductID, TierValue Desc
SQL FIDDLE

How to count records by grouping them in cfWheels?

I have a case where I need to count the number of records grouped by publishing year. I've looked at the documentation, and the net in general, but I can't find what to use.
e.g.
2013 = 100 books published
2012 = 95 books
etc..
Using Oracle SQL, this is done using:
select date_published, count(*)
from publications
group by date_published
order by date_published desc
I'm just wondering how to translate this to CFWheels.
Try this:
publications=model("publication").findAll(
select="date_published, COUNT(date_published) AS publishCount"
, group="date_published"
, order="date_published DESC" );
NB, COUNT() is a case-sensitive command in wheels.
PS, or you can do what matt says - you could even attach it to the model so you could do publications.getPubCountByYear() etc.
This is more of a comment, but because I need the formatting I'm posting it as an answer. Can't you write a query just like a regular query in ColdFusion?
<cfquery name="getCounts" datasource="myDSN">
select date_published, count(*)
from publications
group by date_published
order by date_published desc
</cfquery>