Hi I need to do something like this as a part of a bigger script:
SELECT
GROUP_CONCAT(DISTINCT
CONCAT('(SUM(CASE WHEN ColumnA = "' ,ColumnA, ' "THEN 1 ELSE 0 end))/(select total
from hd_totals where ColumnA = "' ,ColumnA, ' ") AS "' ,ColumnA, ' "'))
FROM table inner join.....
The problem is that I can't do the / operation because it gives an error, even if the select output is a single value.
I don't even know how to use aliases or to store in a variable because it's a rather complex (to me) environment I'm creating here...
What about this : use CAST to have DECIMAL type, and use coalesce to prevent null values?
SELECT
GROUP_CONCAT(DISTINCT
CONCAT('COALESCE(CAST((SUM(CASE WHEN ColumnA = "' ,ColumnA, ' "THEN 1 ELSE 0 end)) AS DECIMAL(10,4)),0)/COALESCE(CAST((select total
from hd_totals where ColumnA = "' ,ColumnA, ' ") AS DECIMAL(10,4)),0.01) AS "' ,ColumnA, ' "'))
FROM table inner join.....
Note : there is an arbitrary constant 0.01 to prevent dividing by 0.
More important note : If I was you I would also add a CASE WHEN to check that you don't divide by 0.
Related
I have a function I am trying to do for a database I am working on for my job. I'm not the most proficient with Access so I apologize if I am not wording this in the best way.
What I am trying to do is create a query/macro that will mimic the behavior as shown
and result into this:
The logic is as follows
1) for each record - take the LEN of the string in StdName. Take that number of characters and UPDATE that to the Name field. The remaining characters after the LEN is moved to the 'SuffixString' Field
2)for each record - count the number of occurrences of the string in the 'StdName' field for any records ON OR BEFORE the index number and UPDATE the 'Name' field with whatever is in there already and concatenate with "_n" where n is the occurence
example: index 1 - has one occurrence of 'Car1' in the StdName Field between record 1 and record 1. index 1 'Name' is changed to Car1_1
example: index 2 - has two occurrences of 'Car1' in the StdName Field between record 1 and record 2. index 2 'Name' is changed to Car1_2
example: index 6 - has one occurrence of 'Car3" in the StdName Field between record 1 and record 6. index 6 'Name' is changed to Car3_1
Can something like this be done with an access query? I've never developed in Access before and my boss really wants to see this function kept inside access instead of being moved in an out of excel.
(I have step 1 setup this way to later put in logic where StdName does not match Name. example: "Car1_1" for Name and StdName "Car2". I realize I could just Concatenate StdName with the function in step 2 in this example i described, but I have a real world purpose of doing it this way)
This will be done on an MDB format
Thank you
You can use my RowCounter function:
SELECT RowCounter(CStr([Index]),False,[StdName])) AS RowID, *
FROM YourTable
WHERE (RowCounter(CStr([Index]),False) <> RowCounter("",True));
or:
SELECT [StdName] & "_" & CStr(RowCounter(CStr([Index]),False,[StdName]))) AS RankedName, *
FROM YourTable
WHERE (RowCounter(CStr([Index]),False) <> RowCounter("",True));
Edit - to update:
UPDATE s_before
SET [Name] = [StdName] & "_" & CStr(RowCounter(CStr([Index]),False,[StdName]))
WHERE (RowCounter(CStr([Index]),False) <> RowCounter("",True));
Code:
Public Function RowCounter( _
ByVal strKey As String, _
ByVal booReset As Boolean, _
Optional ByVal strGroupKey As String) _
As Long
' Builds consecutive RowIDs in select, append or create query
' with the possibility of automatic reset.
' Optionally a grouping key can be passed to reset the row count
' for every group key.
'
' Usage (typical select query):
' SELECT RowCounter(CStr([ID]),False) AS RowID, *
' FROM tblSomeTable
' WHERE (RowCounter(CStr([ID]),False) <> RowCounter("",True));
'
' Usage (with group key):
' SELECT RowCounter(CStr([ID]),False,CStr[GroupID])) AS RowID, *
' FROM tblSomeTable
' WHERE (RowCounter(CStr([ID]),False) <> RowCounter("",True));
'
' The Where statement resets the counter when the query is run
' and is needed for browsing a select query.
'
' Usage (typical append query, manual reset):
' 1. Reset counter manually:
' Call RowCounter(vbNullString, False)
' 2. Run query:
' INSERT INTO tblTemp ( RowID )
' SELECT RowCounter(CStr([ID]),False) AS RowID, *
' FROM tblSomeTable;
'
' Usage (typical append query, automatic reset):
' INSERT INTO tblTemp ( RowID )
' SELECT RowCounter(CStr([ID]),False) AS RowID, *
' FROM tblSomeTable
' WHERE (RowCounter("",True)=0);
'
' 2002-04-13. Cactus Data ApS. CPH
' 2002-09-09. Str() sometimes fails. Replaced with CStr().
' 2005-10-21. Str(col.Count + 1) reduced to col.Count + 1.
' 2008-02-27. Optional group parameter added.
' 2010-08-04. Corrected that group key missed first row in group.
Static col As New Collection
Static strGroup As String
On Error GoTo Err_RowCounter
If booReset = True Then
Set col = Nothing
ElseIf strGroup <> strGroupKey Then
Set col = Nothing
strGroup = strGroupKey
col.Add 1, strKey
Else
col.Add col.Count + 1, strKey
End If
RowCounter = col(strKey)
Exit_RowCounter:
Exit Function
Err_RowCounter:
Select Case Err
Case 457
' Key is present.
Resume Next
Case Else
' Some other error.
Resume Exit_RowCounter
End Select
End Function
I have the query outlined as below. At present it takes over 8 min to run given there are over 8 million records within the zt_Arrival_Data table, while the zt_Tpl_Tuple_Stats_2 tale only carries 9774 records, with the total output of simply 6946 unique records.
In what way can I structure this query to improve performance?
SELECT distinct b.Tuple_ID
, LTRIM(RTRIM(a.ORIGIN_CITY)) + ', ' + LTRIM(RTRIM(a.ORIGIN_STATE)) AS Origin_TX
, LTRIM(RTRIM(a.DESTINATION_CITY)) + ', ' + LTRIM(RTRIM(a.DESTINATION_STATE)) AS Destination_TX
, LTRIM(RTRIM(a.ORIGIN_CITY)) + ' - ' + LTRIM(RTRIM(a.CUSTOMER_NAME)) AS Origin_Customer_TX
, LTRIM(RTRIM(a.ORIGIN_CITY)) + ' - ' + LTRIM(RTRIM(a.DESTINATION_CITY)) AS Origin_Destination_TX
, LTRIM(RTRIM(a.CUSTOMER_NAME)) AS Customer_Name
, LTRIM(RTRIM(a.CUSTOMER_NAME)) + ', ' + LTRIM(RTRIM(a.CUSTOMER_NO)) AS Customer_TX
, CASE
WHEN LTRIM(RTRIM(a.CUSTOMER_TYPE)) = 'C' THEN 'Customer'
WHEN LTRIM(RTRIM(a.CUSTOMER_TYPE)) = 'I' THEN 'Internal'
WHEN LTRIM(RTRIM(a.CUSTOMER_TYPE)) = 'S' THEN 'Shop'
WHEN LTRIM(RTRIM(a.CUSTOMER_TYPE)) = '' THEN 'zUnkown'
ELSE LTRIM(RTRIM(a.CUSTOMER_TYPE))
END AS Customer_Type
, CASE
WHEN a.CARE_OF_NAME = '' THEN 'zUnknown'
ELSE a.CARE_OF_NAME
END AS Care_of_Name
, LTRIM(RTRIM(a.ORIGIN_CITY )) AS Origin_City
, LTRIM(RTRIM(a.ORIGIN_STATE )) AS Origin_State
, LTRIM(RTRIM(a.DESTINATION_CITY )) AS Destination_City
, LTRIM(RTRIM(a.DESTINATION_STATE )) AS Destination_State
, LTRIM(RTRIM(b.BusinessGroup_TX )) AS BusinessGroup_TX
, b.Fleet_TX AS Fleet_TX
, c.Leg_TX AS Leg_TX
FROM zt_Arrival_Data a
INNER JOIN zt_Tpl_Tuple_Stats_2 b
ON LTRIM(RTRIM(a.ORIGIN_CITY)) + ', ' + LTRIM(RTRIM(a.ORIGIN_STATE)) = b.ORIGIN_TX
AND LTRIM(RTRIM(a.DESTINATION_CITY)) + ', ' + LTRIM(RTRIM(a.DESTINATION_STATE)) = b.DESTINATION_TX
AND a.CUSTOMER_NO = b.CUSTOMER_CD
AND a.BUSINESS_GROUP = b.BusinessGroup_TX
AND a.[FLEET_ID (GEN PLANT)] = b.Fleet_TX
JOIN zt_LegMap c ON c.Leg_CD = b.Leg_CD
It is far better to trim the data on data entry where it only has to happen once than to do this sort of thing against a large table in a select.
It is an especially bad design that you you have to concatenate in order to join. You lose the ability to use indexes when you do these things. In SQL Server I would create a calculated persisted column that Ci could join on instead, not sure if mysql has such things. But you should investigate doing this.
From my experience I've learned that when you need to format fields in order to join the tables you should format the columns of the table which has LESS rows to match the one with MORE rows, which must be compared unaltered.
Some idea to start with:
FROM zt_Arrival_Data a
INNER JOIN zt_Tpl_Tuple_Stats_2 b
ON a.ORIGIN_CITY = <format the b table columns to match a.ORIGIN_CITY>
AND a.DESTINATION_STATE = <format the b table columns to match a.DESTINATION_STATE>
AND a.DESTINATION_CITY = <format the b table columns to match a.DESTINATION_CITY>
AND a.ORIGIN_STATE = <format the b table columns to match a.ORIGIN_STATE>
AND a.CUSTOMER_NO = b.CUSTOMER_CD
AND a.BUSINESS_GROUP = b.BusinessGroup_TX
AND a.[FLEET_ID (GEN PLANT)] = b.Fleet_TX
When I set up Allen Browne's ConcatRelated in a query to use a date range, I get ever comment in that range in each comment field. I want to group by an assembly line name but I get each line's comments. My SQL query is below. Any help would be greatly appreciated.
I have tried a sub query but I still get the same result or a syntax error depending on how I format.
SELECT
Asm_Equipment_Rate.Line_Name,
Avg(Asm_Equipment_Rate.Std_Pnls_Lbr_Hr) AS RAsm_Line_Std_Hrs,
Sum(Asm_Prod_Data.Lbr_Hrs) AS RAsm_Line_Total_Hrs,
([RAsm_Line_Std_Hrs]*[RAsm_Line_Total_Hrs]) AS RT100_Pct_Target,
([RT100_Pct_Target]*0.9) AS RT90_Pct_Target,
Sum(Asm_Prod_Data.Produced) AS RTotal_Produced,
Sum(Asm_Prod_Data.Backflushed) AS RTotal_Backflushed,
[RTotal_Produced]/[RT100_Pct_Target] AS RAsm_Line_EFF,
Sum(Asm_Prod_Data.Scrap_Qty) AS RAsm_Scrapped_Panels,
Sum(Asm_Prod_Data.Reworked) AS RAsm_Reworked_Panels,
IIf(([RAsm_Scrapped_Panels]+[RAsm_Reworked_Panels])=0,1,1-
([RAsm_Scrapped_Panels]+[RAsm_Reworked_Panels])/([RAsm_Scrapped_Panels]+
[RAsm_Reworked_Panels]+[RTotal_Produced])) AS RFYP,
ConcatRelated
('Comments',
'Asm_Prod_Data',
'PA_date Between ' & Format([Forms]![Date Prompt]!
[txtBDate],'\#yyyy-m-d\#') & ' And ' & Format([Forms]![Date Prompt]!
[txtEDate],'\#yyyy-m-d\#'),
'Comments',
', ') AS RConCat_Comments
FROM Asm_Equipment_Rate INNER JOIN Asm_Prod_Data ON
Asm_Equipment_Rate.Equipment = Asm_Prod_Data.P_Line
WHERE (((Asm_Prod_Data.PA_Date) Between [Forms]![Date Prompt]![txtBDate]
And [Forms]![Date Prompt]![txtEDate]))
GROUP BY Asm_Equipment_Rate.Line_Name;
Regards,
Bill
change the WHERE clause to
'PA_date Between ' &
Format([Forms]![Date Prompt]![txtBDate],'\#yyyy-m-d\#') &
' And ' & Format([Forms]![Date Prompt]![txtEDate],'\#yyyy-m-d\#') &
' And P_Line=' & Asm_Prod_Data.P_Line,
You'll need to quote the value if P_Line is text.
Also, I think when you call a function you need to use double quotes inside the function call, although if what you have there is working, that's not true. Maybe it's changed for later Access versions.
EDIT: I mean the WHERE clause in the function call
Try this
SELECT
Asm_Equipment_Rate.Line_Name,
ConcatRelated
('Comments',
'Asm_Prod_Data',
'PA_date Between '
& Format([Forms]![Date Prompt]![txtBDate],'\#yyyy-m-d\#')
& ' And ' & Format([Forms]![Date Prompt]![txtEDate],'\#yyyy-m-d\#')
& ' And P_Line=' & Asm_Prod_Data.P_Line,
'Comments',
', ') AS RConCat_Comments
FROM Asm_Equipment_Rate INNER JOIN Asm_Prod_Data
ON Asm_Equipment_Rate.Equipment = Asm_Prod_Data.P_Line
WHERE (((Asm_Prod_Data.PA_Date) Between [Forms]![Date Prompt]![txtBDate]
And [Forms]![Date Prompt]![txtEDate]))
GROUP BY Asm_Equipment_Rate.Line_Name,
ConcatRelated
('Comments',
'Asm_Prod_Data',
'PA_date Between '
& Format([Forms]![Date Prompt]![txtBDate],'\#yyyy-m-d\#')
& ' And ' & Format([Forms]![Date Prompt]![txtEDate],'\#yyyy-m-d\#')
& ' And P_Line=' & Asm_Prod_Data.P_Line,
'Comments',
', ');
It's unfortunate but the GROUP BY expression has to be identical to the one in the SELECT clause, no matter how complex.
I'm developing an application using vb.net2008 with database as msaccess. I've designed a table in database having columns IN_TIME and OUT_TIME in format HH:MM:SS . I want a result as TOT_TIME which will display difference between these two columns. I've written a query for this, now i'm facing a problem that i dont want to display result if IN_TIME is less than 8:00:00 AM else display result. I have used CASE WHEN but it didnt worked, help me out.
I've tried this so far
SELECT *
(CASE WHEN LATE_LIMIT > '" + date3 + "'
THEN ROUND(([PM_OUT]-[OVERIME_LIMIT]),2)
ELSE 'N' )AS OverTime
FROM DTR_REC
You are missing a comma and an END case:
SELECT *
,(CASE WHEN LATE_LIMIT > '" + date3 + "'
THEN ROUND(([PM_OUT]-[OVERIME_LIMIT]),2)
ELSE 'N' END)AS OverTime
FROM DTR_REC
But I'm not sure if Access supports CASE statements. If not does this work:
SELECT *
,IIF(LATE_LIMIT > '" + date3 + "', ROUND(([PM_OUT]-[OVERIME_LIMIT]),2),'N') AS OverTime
FROM DTR_REC
I have a query which i am using to filter the grid
SELECT * FROM Resources
WHERE ResourceName ='" + ResourceName + "'
AND Status = '" + status + "' "
and my grid looks like this
ResourceID|ResourceName|Status
I had added the ResorceName and Status in a dropdown for filtering the grid now my problem is that in this select statement if any of the paramaters is null the data is not Binded to the grid but if I pass both the parameters it filters the grid and gives the required row or filtered row from the grid... Can anyone tell me how do I write select statement if any of the parameter is null.
Have a look it the below post on catch all queries
Catch All Examples
In terms of fixing your problem quickly, something like this would work...
Select * From Resources Where (ResourceName = '"+ ResourceName + "' OR ResourceName IS NULL) AND (Status = '" + Status +"' OR Status IS NULL)
That however is NOT an acceptable piece of code, as it is vulnerable to SQL injection. In essence, suppose the ResourceName that is passed in is
'; Drop Table Resources; --
You probably don't need me to tell you what that does.
My advice is to ALWAYS make use of SQLCommand objects in .Net - also known as "Prepared Statements" in other languages. It prevents these kind of tricks...
SELECT * FROM Resources
WHERE (ResourceName = CASE WHEN '" + ResourceName + "' IS NULL THEN ResourceName ELSE '" + ResourceName + "' END) //do same for other parameter