ExecuteSQL Concatenate string and integer - filemaker

I am using trying to populate a dropdown using magicVaueList hack and ExecuteSQl and I am having trouble with joining a text and number.
Here is my code:
MVL_Dropdown ( ExecuteSQL ( "select L.Product + GetAsText( L.Quantity )
from T08_ESTIMATES E
join T09_EST_LINE_ITEMS L on E.ID_Estimate = L.id_estimate
where E.ID_Estimate = ? "; ""; ""; T19_TASKS::preitem ) )
The trouble I get is with the + GetAsText( L.Quantity ) where I have also tried & GetAsText( L.Quantity ) will no results but if I was to remov ethe join like:
MVL_Dropdown ( ExecuteSQL ( "select L.Product
from T08_ESTIMATES E
join T09_EST_LINE_ITEMS L on E.ID_Estimate = L.id_estimate
where E.ID_Estimate = ? "; ""; ""; T19_TASKS::preitem ) )
Then it works minus the fact that I will need both values. I'm therefore certain the problem exists Concatenating my text and number but I'm quite new to FileMaker and not sure what to use to get it to work.
.
Any help appreciated.

For anyone wondering i had to use a double pipe like so:
L.Product || ' - ' || L.Quantity
MVL_Dropdown ( ExecuteSQL ( "SELECT L.Product || ' - ' || L.Quantity || ' off'
FROM T08_ESTIMATES E
JOIN T09_EST_LINE_ITEMS L ON E.ID_Estimate = L.id_estimate
WHERE E.ID_Estimate = ? "; ""; ""; T19_TASKS::preitem ) )

STRVAL - Converts a value of any type to a character string
Here I wanted to concatenate an integer "Quantity" and string "Units":
ExecuteSQL ( "
SELECT p.Description, STRVAL ( m.Quantity ) || p.Units
FROM JobMaterials m
JOIN Products p
ON m.kf_Product = p.kp_ProductID
WHERE m.kf_JobID = ?
" ;
"¦" ; "¶" ;
Jobs::kp_JobID
)

Related

converting sql statement back to lambda expression

I have the query below, and its sql code. It's running really slow, so it was re written in sql, now I'm just not sure how to convert the sql back to a lambda expression.
This is the part of the expression giving me the problems, somewhere in
r.RecordProducts.Any()
records = records
.Include(r => r.Employer)
.Include(r => r.Contractor)
.Include(r => r.RecordProducts)
.ThenInclude(rp => rp.ProductDefendant.Defendant)
.Where(r => EF.Functions.Like(r.Employer.DefendantCode, "%" + input.DefendantCode + "%")
|| EF.Functions.Like(r.Contractor.DefendantCode, "%" + input.DefendantCode + "%")
|| r.RecordProducts.Any(rp => EF.Functions.Like(rp.ProductDefendant.Defendant.DefendantCode, "%" + input.DefendantCode + "%") && rp.IsActive == true));
the any clause does an exist and some funky stuff in the sql where clause below
SELECT [t].[Id], [t].[StartDate], [t].[EndDate], [t].[WitnessName], [t].[SourceCode], [t].[JobsiteName], [t].[ShipName], [t].[EmployerCode]
FROM (
SELECT DISTINCT [r].[RecordID] AS [Id], [r].[StartDate], [r].[EndDate], [r.Witness].[FullName] AS [WitnessName], CASE
WHEN [r].[SourceID] IS NOT NULL
THEN [r.Source].[SourceCode] ELSE N'zzzzz'
END AS [SourceCode], CASE
WHEN [r].[JobsiteID] IS NOT NULL
THEN [r.Jobsite].[JobsiteName] ELSE N'zzzzz'
END AS [JobsiteName], CASE
WHEN [r].[ShipID] IS NOT NULL
THEN [r.Ship].[ShipName] ELSE N'zzzzz'
END AS [ShipName], CASE
WHEN [r].[EmployerID] IS NOT NULL
THEN [r.Employer].[DefendantCode] ELSE N'zzzzz'
END AS [EmployerCode]
FROM [Records] AS [r]
LEFT JOIN [Ships] AS [r.Ship] ON [r].[ShipID] = [r.Ship].[ShipID]
LEFT JOIN [Jobsites] AS [r.Jobsite] ON [r].[JobsiteID] = [r.Jobsite].[JobsiteID]
LEFT JOIN [Sources] AS [r.Source] ON [r].[SourceID] = [r.Source].[SourceID]
LEFT JOIN [Witnesses] AS [r.Witness] ON [r].[WitnessID] = [r.Witness].[WitnessID]
LEFT JOIN [Defendants] AS [r.Contractor] ON [r].[ContractorID] = [r.Contractor].[DefendantID]
LEFT JOIN [Defendants] AS [r.Employer] ON [r].[EmployerID] = [r.Employer].[DefendantID]
WHERE ([r].[IsActive] = 1) AND (([r.Employer].[DefendantCode] LIKE (N'%' + 'cert') + N'%' OR [r.Contractor].[DefendantCode] LIKE (N'%' + 'cert') + N'%') OR EXISTS (
SELECT 1
FROM [Records_Products] AS [rp]
INNER JOIN [Product_Defendant] AS [rp.ProductDefendant] ON [rp].[DefendantProductID] = [rp.ProductDefendant].[DefendantProductID]
INNER JOIN [Defendants] AS [rp.ProductDefendant.Defendant] ON [rp.ProductDefendant].[DefendantID] = [rp.ProductDefendant.Defendant].[DefendantID]
WHERE ([rp.ProductDefendant.Defendant].[DefendantCode] LIKE (N'%' + 'cert') + N'%' AND ([rp].[IsActive] = 1)) AND ([r].[RecordID] = [rp].[RecordID])))
) AS [t]
ORDER BY [t].[SourceCode]
OFFSET 0 ROWS FETCH NEXT 500 ROWS ONLY
Here is the new sql that works better, just not sure how to convert it back to a lambda expression
SELECT [t].[Id]
,[t].[StartDate]
,[t].[EndDate]
,[t].[WitnessName]
,[t].[SourceCode]
,[t].[JobsiteName]
,[t].[ShipName]
,[t].[EmployerCode]
FROM (
SELECT DISTINCT [r].[RecordID] AS [Id]
,[r].[StartDate]
,[r].[EndDate]
,[r.Witness].[FullName] AS [WitnessName]
,CASE
WHEN [r].[SourceID] IS NOT NULL
THEN [r.Source].[SourceCode]
ELSE N'zzzzz'
END AS [SourceCode]
,CASE
WHEN [r].[JobsiteID] IS NOT NULL
THEN [r.Jobsite].[JobsiteName]
ELSE N'zzzzz'
END AS [JobsiteName]
,CASE
WHEN [r].[ShipID] IS NOT NULL
THEN [r.Ship].[ShipName]
ELSE N'zzzzz'
END AS [ShipName]
,CASE
WHEN [r].[EmployerID] IS NOT NULL
THEN [r.Employer].[DefendantCode]
ELSE N'zzzzz'
END AS [EmployerCode]
FROM [Records] AS [r]
LEFT JOIN [Ships] AS [r.Ship] ON [r].[ShipID] = [r.Ship].[ShipID]
LEFT JOIN [Jobsites] AS [r.Jobsite] ON [r].[JobsiteID] = [r.Jobsite].[JobsiteID]
LEFT JOIN [Sources] AS [r.Source] ON [r].[SourceID] = [r.Source].[SourceID]
LEFT JOIN [Witnesses] AS [r.Witness] ON [r].[WitnessID] = [r.Witness].[WitnessID]
LEFT JOIN [Defendants] AS [r.Contractor] ON [r].[ContractorID] = [r.Contractor].[DefendantID]
LEFT JOIN [Defendants] AS [r.Employer] ON [r].[EmployerID] = [r.Employer].[DefendantID]
LEFT JOIN (
SELECT [rp].[RecordID]
FROM [Records_Products] AS [rp]
INNER JOIN [Product_Defendant] AS [rp.ProductDefendant] ON [rp].[DefendantProductID] = [rp.ProductDefendant].[DefendantProductID]
INNER JOIN [Defendants] AS [rp.ProductDefendant.Defendant] ON [rp.ProductDefendant].[DefendantID] = [rp.ProductDefendant.Defendant].[DefendantID]
WHERE (
[rp.ProductDefendant.Defendant].[DefendantCode] LIKE (N'%' + 'cert') + N'%'
AND ([rp].[IsActive] = 1)
)
) AS RecordProduct ON [r].[RecordID] = RecordProduct.[RecordID]
WHERE ([r].[IsActive] = 1)
AND (
(
[r.Employer].[DefendantCode] LIKE (N'%' + 'cert') + N'%'
OR [r.Contractor].[DefendantCode] LIKE (N'%' + 'cert') + N'%'
)
OR RecordProduct.RecordID IS NOT NULL --OR EXISTS ( -- SELECT 1 -- FROM [Records_Products] AS [rp] -- INNER JOIN [Product_Defendant] AS [rp.ProductDefendant] ON [rp].[DefendantProductID] = [rp.ProductDefendant].[DefendantProductID] -- INNER JOIN [Defendants] AS [rp.ProductDefendant.Defendant] ON [rp.ProductDefendant].[DefendantID] = [rp.ProductDefendant.Defendant].[DefendantID] -- WHERE ([rp.ProductDefendant.Defendant].[DefendantCode] LIKE (N'%' + 'cert') + N'%' -- AND ([rp].[IsActive] = 1)) AND ([r].[RecordID] = [rp].[RecordID]) -- ) )) AS [t]ORDER BY [t].[SourceCode]OFFSET 0 ROWS FETCH NEXT 500 ROWS ONLY
)
)
The linq expression you supplied and the SQL generated do not match. For one, the linq expression is performing an Include on the various related tables which would have included all of those entity columns in the top-level SELECT which are not present in your example SQL. I also don't see conditions in the Linq expression for the Take 500 & OrderBy, or IsActive assertion on Record.
To be able to help determine the source of any performance concern we need to see the complete Linq expression and the resulting SQL.
Looking at the basis of the Linq expression you provided:
records = records
.Include(r => r.Employer)
.Include(r => r.Contractor)
.Include(r => r.RecordProducts)
.ThenInclude(rp => rp.ProductDefendant.Defendant)
.Where(r => EF.Functions.Like(r.Employer.DefendantCode, "%" + input.DefendantCode + "%")
|| EF.Functions.Like(r.Contractor.DefendantCode, "%" + input.DefendantCode + "%")
|| r.RecordProducts.Any(rp => EF.Functions.Like(rp.ProductDefendant.Defendant.DefendantCode, "%" + input.DefendantCode + "%") && rp.IsActive == true));
There are a few suggestions I can make:
There is no need for the Functions.Like. You should be able to achieve the same with Contains.
Avoid using Include and instead utilize Select to retrieve the columns from the resulting structure that you actually need. Populate these into ViewModels or consume them in the code. The less data you pull back, the better optimized the SQL can be for indexing, and the less data pulled across the wire. Consuming entities also leads to unexpected lazy-load scenarios as systems mature and someone forgets to Include a new relation.
.
records = records
.Where(r => r.IsActive
&& (r.Employer.DefendantCode.Contains(input.DefendantCode)
|| r.Contractor.DefendantCode.Contains(input.DefendantCode)
|| r.RecordProducts.Any(rp => rp.IsActive
&& rp.ProductDefendant.Defendant.DefendantCode.Contains(input.DefendantCode))
.OrderBy(r => r.SourceCode)
.Select(r => new RecordViewModel
{
// Populate the data you want here.
}).Take(500).ToList();
This also adds the IsActive check, OrderBy, and Take(500) based on your sample SQL.

EF Core FromSql Returning Odd Error Message

This code throws an exception when rawVoters.Count() is called:
string sql = #"select * from Voters as v
inner join Homes as h on v.HomeID = h.ID
inner join Locations as l on h.LocationID = l.ID
inner join Streets as s on l.StreetID = s.ID
inner join Cities as c on s.CityID = c.ID
inner join VoterAgencies as va on v.CountyID = va.CountyID and v.VoterID = va.VoterID
where (va.AgencyID = #agencyID)
and (c.Name like '%' + #city + '%')
and (v.FirstName like '%' + #firstName + '%')
and (v.LastName like '%' + #lastName + '%')
and (s.Name like '%' + #street + '%')
and ((#voterID = 0) or (v.VoterID = #voterID))";
List<SqlParameter> parameters = new List<SqlParameter>();
parameters.Add( new SqlParameter( "#agencyID", agencyID ) );
parameters.Add( new SqlParameter( "#city", model.City ) );
parameters.Add( new SqlParameter( "#firstName", model.FirstName ) );
parameters.Add( new SqlParameter( "#lastName", model.LastName ) );
parameters.Add( new SqlParameter( "#street", model.Street ) );
parameters.Add( new SqlParameter( "#voterID", model.VoterID ) );
IQueryable<Voter> rawVoters = _context.Voters
.AsNoTracking()
.FromSql( sql, parameters.ToArray() );
int numVoters = 0;
try
{
numVoters = rawVoters.Count();
}
catch( Exception e )
{
int i = 9;
i++;
}
The error message is:
"The column 'ID' was specified multiple times for 'v'."
I thought this might be because EF Core doesn't like the "as x" phrasing, so I substituted the table names for each of the identifiers...and got the same error message.
I'm curious as to what's going on here.
The problem was that the T-SQL was returning all fields (select *). Under EF Core, the returned fields must match the fields specified for the entity being returned, in this case Voter.
An inner join, like the one I was using, by default returns far more than just the Voter fields.
Changing the SQL to be select v.* (where v is the alias for Voters) solved the problem.
Hence you're just getting the Count,you can specify your column name as shown below.Then no issues :)
string sql = #"select v.ID from Voters as v

Using IndexOf and/Or Substring to parse data into separate columns

I am working on migrating data from one database to another for a hospital. In the old database, the doctor's specialty IDs are all in one column (swvar_specialties), each separated by commas. In the new database, each specialty ID will have it's own column (example: Specialty1_PrimaryID, Specialty2_PrimaryID, Specialty3_PrimaryID, etc). I am trying to export the data out of the old database and separate these into these separate columns. I know I can use indexof and substring to do this - I just need help with the syntax.
So this query:
Select swvar_specialties as Specialty1_PrimaryID
From PhysDirectory
might return results similar to 39,52,16. I need this query to display Specialty1_PrimaryID = 39, Specialty2_PrimaryID = 52, and Specialty3_PrimaryID = 16 in the results. Below is my query so far. I will eventually have a join to pull the specialty names from the specialties table. I just need to get this worked out first.
Select pd.ref as PrimaryID, pd.swvar_name_first as FirstName, pd.swvar_name_middle as MiddleName,
pd.swvar_name_last as LastName, pd.swvar_name_suffix + ' ' + pd.swvar_name_degree as NameSuffix,
pd.swvar_birthdate as DateOfBirth,pd.swvar_notes as AdditionalInformation, 'images/' + '' + pd.swvar_photo as ImageURL,
pd.swvar_philosophy as PhilosophyOfCare, pd.swvar_gender as Gender, pd.swvar_specialties as Specialty1_PrimaryID, pd.swvar_languages as Language1_Name
From PhysDirectory as pd
The article Split function equivalent in T-SQL? provides some details on how to use a split function to split a comma-delimited string.
By modifying the table-valued function in presented in this article to provide an identity column we can target a specific row such as Specialty1_PrimaryID:
/*
Splits string into parts delimitered with specified character.
*/
CREATE FUNCTION [dbo].[SDF_SplitString]
(
#sString nvarchar(2048),
#cDelimiter nchar(1)
)
RETURNS #tParts TABLE (id bigint IDENTITY, part nvarchar(2048) )
AS
BEGIN
if #sString is null return
declare #iStart int,
#iPos int
if substring( #sString, 1, 1 ) = #cDelimiter
begin
set #iStart = 2
insert into #tParts
values( null )
end
else
set #iStart = 1
while 1=1
begin
set #iPos = charindex( #cDelimiter, #sString, #iStart )
if #iPos = 0
set #iPos = len( #sString )+1
if #iPos - #iStart > 0
insert into #tParts
values ( substring( #sString, #iStart, #iPos-#iStart ))
else
insert into #tParts
values( null )
set #iStart = #iPos+1
if #iStart > len( #sString )
break
end
RETURN
END
Your query can the utilise this split function as follows:
Select
pd.ref as PrimaryID,
pd.swvar_name_first as FirstName,
pd.swvar_name_middle as MiddleName,
pd.swvar_name_last as LastName,
pd.swvar_name_suffix + ' ' + pd.swvar_name_degree as LastName,
pd.swvar_birthdate as DateOfBirth,pd.swvar_notes as AdditionalInformation,
'images/' + '' + pd.swvar_photo as ImageURL,
pd.swvar_philosophy as PhilosophyOfCare, pd.swvar_gender as Gender,
(Select part from SDF_SplitString(pd.swvar_specialties, ',') where id=1) as Specialty1_PrimaryID,
(Select part from SDF_SplitString(pd.swvar_specialties, ',') where id=2) as Specialty2_PrimaryID,
pd.swvar_languages as Language1_Name
From PhysDirectory as pd

Zend_DB subselect / subquery how to?

I have this raw sql statement which I am trying to execute through Zend_DB.
$sql = 'SELECT relocationaction.id, relocationaction.vehicle, relocationaction.start, relocationaction.end, relocationaction.return ' .
'FROM relocationaction,
(SELECT vehicle, MAX(end) AS maxend
FROM relocationaction
GROUP BY vehicle) AS co2
WHERE co2.vehicle = relocationaction.vehicle
AND(relocationaction.monitor = 1)
AND (relocationaction.return IS NULL)
AND (start <= ?)
AND relocationaction.end = co2.maxend';
I have found a possible solution using this type of notation, but it is rendered to a totally different and wrong sql statement with joins and strange table names.
$tbl = $this->getDbTable();
$select = $tbl->select()->setIntegrityCheck(false);
$subSelect = $select->from('relocationaction', array('vehicle', 'maxend' => 'MAX(relocationaction.end)'))
->group('vehicle');
$subSelectString = '(' . $subSelect->__toString() . ')';
$select ->from(
array('relocationaction'), array('id', 'date' => 'start', 'enddate' => 'end', 'return'),
array('co2' => $subSelectString)
)
->joinLeft('exhibitvehicle', 'exhibitvehicle.id = relocationaction.vehicle', array())
->where('co2.vehicle = relocationaction.vehicle')
->where('relocationaction.monitor = 1')
->where('relocationaction.return IS NULL')
->where('start <= ?', $start->get('yyyy-MM-dd'))
->where('relocationaction.end = co2.maxend');
Can anyone please give me a hint?
Thanks
Jesse
UPDATE
This is the result of the second expression (total rubbish)
SELECT `relocationaction`.`vehicle`,
MAX(relocationaction.end) AS `maxend`,
`relocationaction_2`.`id`,
`relocationaction_2`.`start` AS `date`,
`relocationaction_2`.`end` AS `enddate`,
`relocationaction_2`.`return`
FROM `relocationaction`
INNER JOIN `(
SELECT ``relocationaction``.``vehicle``,
MAX(relocationaction.end) AS ``maxend`` FROM ``relocationaction`` GROUP BY ``vehicle``)`.`relocationaction` AS `relocationaction_2`
LEFT JOIN `exhibitvehicle` ON exhibitvehicle.id = relocationaction.vehicle
WHERE (col2.vehicle = relocationaction.vehicle)
AND (relocationaction.monitor = 1)
AND (relocationaction.return IS NULL)
AND (start <= '2013-05-08')
AND (relocationaction.end = col2.maxend)
GROUP BY `vehicle`
If you use a string in from(), Zend_Db_Select will consider it to be a table name so it escapes it.
The solution is to wrap your subselect into a Zend_Db_Expr.
$tbl = $this->getDbTable();
$select = $tbl->select()->setIntegrityCheck(false);
$subSelect = $select->from('relocationaction', array('vehicle', 'maxend' => 'MAX(relocationaction.end)'))
->group('vehicle');
$subSelectString = '(' . $subSelect->__toString() . ')';
$select ->from(
array('relocationaction'), array('id', 'date' => 'start', 'enddate' => 'end', 'return'),
array('co2' => new Zend_Db_Expr($subSelectString))
)
->joinLeft('exhibitvehicle', 'exhibitvehicle.id = relocationaction.vehicle', array())
->where('co2.vehicle = relocationaction.vehicle')
->where('relocationaction.monitor = 1')
->where('relocationaction.return IS NULL')
->where('start <= ?', $start->get('yyyy-MM-dd'))
->where('relocationaction.end = co2.maxend');
Ok here we go. I tried hard to find a solution with Zend_Db_Table but failed big time. That's why I finally did it with PDO, as suggested by #user466764. Thanks for your help.
$tbl = $this->getDbTable();
$query = 'SELECT relocationaction.id,
relocationaction.vehicle,
relocationaction.start,
relocationaction.end,
relocationaction.return
FROM relocationaction
(SELECT vehicle, MAX(end) AS maxend
FROM relocationaction
GROUP BY vehicle) AS co2
WHERE co2.vehicle = relocationaction.vehicle
AND(relocationaction.monitor = 1)
AND (relocationaction.return IS NULL)
AND (start <= "' . $start->get('yyyy-MM-dd') . '")
AND relocationaction.end = co2.maxend';
$sth = $tbl->getAdapter()->prepare($query);
$sth->execute();
$entries = $sth->fetchAll();

How to add logic to my SQL query to include/exclude search parameters?

Using SQL Server 2008R2, I have here is a simple query:
SELECT *
FROM ItemData
WHERE FREETEXT(Title, '"' + #OriginalSearchTerm + '"')
AND ( WebsiteID=#WebsiteID AND GeoCity = #GeoCity AND GeoState = #GeoState )
ORDER BY ItemListID DESC
This is all fine when there is a valid value for #GeoCity and #GeoState. However there will be scenarios where #GeoCity = -1 and/or #GeoState = -1.
I would rather not write entire separate queries for these cases, although this would work just fine.
How can I optimize the current query to do just this?
Thanks.
-- This might be more efficient as OR statement executes block for each OR statement.
SELECT *
FROM ItemData
WHERE FREETEXT(Title, '"' + #OriginalSearchTerm + '"')
AND ( WebsiteID=#WebsiteID AND
(GeoCity = ISNULL(#GeoCity,-1)) AND
(GeoState = ISNULL(GeoState,-1))
ORDER BY ItemListID DESC
I'm not sure what you want the query to do when #GeoCity = -1 and/or #GeoState = -1. Assuming you want to exclude the GeoCity = #GeoCity and/or GeoState = #GeoState conditions in that case, here's the query:
SELECT *
FROM ItemData
WHERE FREETEXT(Title, '"' + #OriginalSearchTerm + '"')
AND ( WebsiteID=#WebsiteID AND
(#GeoCity = -1 OR GeoCity = #GeoCity) AND
(#GeoState = -1 OR GeoState = #GeoState) )
ORDER BY ItemListID DESC