Add GROUP BY clause to crystal report - crystal-reports

I have a report with a query that used to contain a client-id for each item. The client (the boss) wanted multiple clients for each record. That was easy - replace the client-id field with a new table ItemClients(item-id, client-id) and join on item-id.
The problem is now the reports - of course each item is duplicated for each time there is a client, BUT i WANT ONLY ONE COPY OF THE ITEM IN THE REPORT - irrespective of how many clients there are to an item. Also, there is the ability to filter the report by client, which I can do fine in MySql and worked fine in the previous single-client version.
My solution is to add a group by item-id clause to the query (MySql allows this). The problem is how to add the group by clause to the report. Any attempt to group gets interpreted as a report grouping, which I don't want. I tried to make the whole query as a command, which worked for a while, but now the whole report blows up, crashing my web server.
Any insights would be helpful. thanks.
(edit)
Here's the (hybrid) code in the command, the GROUP BY clause was added by me, the rest was scraped from crystal's show sql command and modified. (btw, this is a sub-report)
SELECT `ITEM`.`Date`, `ITEM`.`Started`, `ITEM`.`Stopped`, `TERM`.`Terminal`, `ITEM`.`TonnesLoaded`, `ITEM`.`LoadID`,
`ITEM`.`TotalLoaded`, `ITEM`.`ToGo`, `ITEM`.`OrderId`,
`COM`.`Commodity`,
`berths1`.`Berth`,
`CQ`.`LotNo`, `CQ`.`CategoryID`,
`IC`.`ClientId`
FROM `berths` `berths1`
INNER JOIN `Items` `ITEM` ON `berths1`.`BerthID`=`ITEM`.`BerthID`
INNER JOIN `terminals` `TERM` ON `berths1`.`TerminalID`=`TERM`.`TerminalID`
INNER JOIN `Quantities` `CQ` ON `ITEM`.`ItemId`=`CQ`.`ItemId`
AND `ITEM`.`OrderId`=`CQ`.`OrderId`
INNER JOIN `commodities` `COM` ON `CQ`.`CommodityID`=`COM`.`CommodityID`
LEFT OUTER JOIN `ItemClients` `IC` ON `CQ`.`OrderId`=`IC`.`OrderId`
AND `CQ`.`ItemId`=`IC`.`ItemId`
WHERE `ITEM`.`OrderId`={?Pm-details.OrderId}
AND ( {?Pm-?Category}=0 AND {?Pm-?ClientId}=0 )
OR (
`CQ`.CategoryID>0
AND `CQ`.CategoryID = {?Pm-?Category}
AND ( {?Pm-?ClientId}=0 OR IC.ClientId = {?Pm-?ClientId} )
)
OR ( {?Pm-?ClientId}>0 AND IC.ClientId = {?Pm-?ClientId} AND {?Pm-?Category}=0 )
GROUP BY `ITEM`.`ItemId`
ORDER BY `ITEM`.`Date`, `ITEM`.`Started`, `ITEM`.`LoadID`

Related

Kentico GET Form Data

I am currently trying to use the Kentico API to gather the data from all forms within Kentico.
So far I've found that there are two places to view form data and they can be found at these endpoints:
/rest/cms.forms <---- Returns all form definitions (excluding field data types
/rest/bizformitem.bizform.FORM_NAME/ <---- Returns all form data (inserted by end users)
What I am trying to do is keep a record of all of the form data on a daily basis. Is there a better way to do this using the API rather than making 'x' number of calls (one per form).
EDIE: Out of 100+ forms I only need to pull 15-20 of them on a daily basis.
You can get all in sql and it depends how many forms you have. Each form is separate sql table that has a record in CMS_Class table
-- this will give the list of all tables that you need query
select ClassTableName from CMS_Class where ClassIsForm = 1
Then you can find out the ones that were updated let say with in the 24 hrs
SELECT
[db_name] = d.name
, [table_name] = SCHEMA_NAME(o.[schema_id]) + '.' + o.name
, s.last_user_update
FROM sys.dm_db_index_usage_stats s
JOIN sys.databases d ON s.database_id = d.database_id
JOIN sys.objects o ON s.[object_id] = o.[object_id]
WHERE o.[type] = 'U'
AND s.last_user_update IS NOT NULL
AND s.last_user_update BETWEEN DATEADD(day, -1, GETDATE()) AND GETDATE()
and s.[object_id] in (select OBJECT_ID(ClassTableName)
from CMS_Class where ClassIsForm =1 )
You might have a few hundred forms... to go and query few hundred tables might be unproductive. I usually get 18-20 out 100+ we have.
There is Kentico API (not a REST API) that allows you to get all data you need at code behind. You can find examples here.

Filtering in join query

Using crystal reports version 14, MS sql server 2008
I am joining two tables and I need to filter in the join, so if a certain value exists in one of the table, I want to join to that record, if it does not exist, I want to have a null-record. I.e:
select * from sample left outer join test
on(sample.sample_number=test.sample_number and test.name='PREP')
I can run that in Sql server studio and get exactly what I want
What I can get in crystal reports is
select * from sample left outer join test
on(sample.sample_number=test.sample_number)
where test.name='PREP'
In the latter case, rows where test.name='PREP' does not exist will be removed and if there are samples that have no test.name='PREP', those samples will be removed.
Are there any ways I can do this in CR 14?
dummy tables:
Sample
sample_number,name
1,A
2,B
3,C
Test
sample_number,name
1,PREP
1,SOMETHING
2,SOMETHING
3,SOMETHING_ELSE
3,PREP
What I want:
1,A,1,PREP
2,B,NULL,NULL
3,C,3,PREP
(of course there are more fields in the tables and a selection of which fields, but this should illustrate what I want)
I know I can make views and query them directly in crystal, but if possible, I would avoid doing that.
Bah, found it:
Database expert - add table, select data source, add command. Then a custom sql can be added.

Converting complex query with inner join to tableau

I have a query like this, which we use to generate data for our custom dashboard (A Rails app) -
SELECT AVG(wait_time) FROM (
SELECT TIMESTAMPDIFF(MINUTE,a.finished_time,b.start_time) wait_time
FROM (
SELECT max(start_time + INTERVAL avg_time_spent SECOND) finished_time, branch
FROM mytable
WHERE name IN ('test_name')
AND status = 'SUCCESS'
GROUP by branch) a
INNER JOIN
(
SELECT MIN(start_time) start_time, branch
FROM mytable
WHERE name IN ('test_name_specific')
GROUP by branch) b
ON a.branch = b.branch
HAVING avg_time_spent between 0 and 1000)t
GROUP BY week
Now I am trying to port this to tableau, and I am not being able to find a way to represent this data in tableau. I am stuck at how to represent the inner group by in a calculated field. I can also try to just use a custom sql data source, but I am already using another data source.
columns in mytable -
start_time
avg_time_spent
name
branch
status
I think this could be achieved new Level Of Details formulas, but unfortunately I am stuck at version 8.3
Save custom SQL for rare cases. This doesn't look like a rare case. Let Tableau generate the SQL for you.
If you simply connect to your table, then you can usually write calculated fields to get the information you want. I'm not exactly sure why you have test_name in one part of your query but test_name_specific in another, so ignoring that, here is a simplified example to a similar query.
If you define a calculated field called worst_case_test_time
datediff(min(start_time), dateadd('second', max(start_time), avg_time_spent)), which seems close to what your original query says.
It would help if you explained what exactly you are trying to compute. It appears to be some sort of worst case bound for avg test time. There may be an even simpler formula, but its hard to know without a little context.
You could filter on status = "Success" and avg_time_spent < 1000, and place branch and WEEK(start_time) on say the row and column shelves.
P.S. Your query seems a little off. Don't you need an aggregation function like MAX or AVG after the HAVING keyword?

Transact-SQL Ambiguous column name

I'm having trouble with the 'Ambiguous column name' issue in Transact-SQL, using the Microsoft SQL 2012 Server Management Studio.
I´ve been looking through some of the answers already posted on Stackoverflow, but they don´t seem to work for me, and parts of it I simply don´t understand or loses the general view of.
Executing the following script :
USE CDD
SELECT Artist, Album_title, track_title, track_number, Release_Year, EAN_code
FROM Artists AS a INNER JOIN CD_Albumtitles AS c
ON a.artist_id = c.artist_id
INNER JOIN Track_lists AS t
ON c.title_id = t.title_id
WHERE track_title = 'bohemian rhapsody'
triggers the following error message :
Msg 209, Level 16, State 1, Line 3
Ambiguous column name 'EAN_code'.
Not that this is a CD database with artists names, album titles and track lists. Both the tables 'CD_Albumtitles' and 'Track_lists' have a column, with identical EAN codes. The EAN code is an important internationel code used to uniquely identify CD albums, which is why I would like to keep using it.
You need to put the alias in front of all the columns in your select list and your where clause. You're getting that error because one of the columns you have currently is coming from multiple tables in your join. If you alias the columns, it will essentially pick one or the other of the tables.
SELECT a.Artist,c.Album_title,t.track_title,t.track_number,c.Release_Year,t.EAN_code
FROM Artists AS a INNER JOIN CD_Albumtitles AS c
ON a.artist_id = c.artist_id
INNER JOIN Track_lists AS t
ON c.title_id = t.title_id
WHERE t.track_title = 'bohemian rhapsody'
so choose one of the source tables, prefixing the field with the alias (or table name)
SELECT Artist,Album_title,track_title,track_number,Release_Year,
c.EAN_code -- or t.EAN_code, which should retrieve the same value
By the way, try to prefix all the fields (in the select, the join, the group by, etc.), it's easier for maintenance.

SQL Select rows by comparison of value to aggregated function result

I have a table listing (gameid, playerid, team, max_minions) and I want to get the players within each team that have the lowest max_minions (within each team, within each game). I.e. I want a list (gameid, team, playerid_with_lowest_minions) for each game/team combination.
I tried this:
SELECT * FROM MinionView GROUP BY gameid, team
HAVING MIN(max_minions) = max_minions;
Unfortunately, this doesn't seem to work as it seems to select a random row from the available rows for each (gameid, team) and then does the HAVING comparison. If the randomly selected row doesn't match, it's simply skipped.
Using WHERE won't work either since you can't use aggregate functions within WHERE clauses.
LIMIT won't work since I have many more games and LIMIT limits the total number of rows returned.
Is there any way to do this without adding another table/view that contains (gameid, teamid, MIN(max_minions))?
Example data:
sqlite> SELECT * FROM MinionView;
gameid|playerid|team|champion|max_minions
21|49|100|Champ1|124
21|52|100|Champ2|18
21|53|100|Champ3|303
21|54|200|Champ4|356
21|57|200|Champ5|180
21|58|200|Champ6|21
64|49|100|Champ7|111
64|50|100|Champ8|208
64|53|100|Champ9|8
64|54|200|Champ0|226
64|55|200|ChampA|182
64|58|200|ChampB|15
...
Expected result (I mostly care about playerid, but included champion, max_minions here for better overview):
21|52|100|Champ2|18
21|58|200|Champ6|21
64|53|100|Champ9|8
64|58|200|ChampB|15
...
I'm using Sqlite3 under Python 3.1 if that matters.
This is in SQL Server, hopefully the syntax works for you too:
SELECT
MV.*
FROM
(
SELECT
team, gameid, min(max_minions) as maxmin
FROM
MinionView
GROUP BY
team, gameid
) groups
JOIN MinionView MV ON
MV.team = groups.team
AND MV.gameid = groups.gameid
AND MV.max_minions = groups.maxmin
In words, first you make the usual grouping query (the nested one). At this point you have the min value for each group but you don't know to which row it belongs. For this you join with the original table and match the "keys" (team, game and min) to get the other columns as well.
Note that if a team will have more than one member with the same value for max_minions then all these rows will be selected. If you only want one of them then that's probably a bit more complicated.