SQL Server Stored Procedure Multiple Condtions - sql

I have this LINQ in C#, which I have to convert to a SQL query. And I am not sure how to do multiple filtering based on conditions:
var geofenceReport = companyContext.GeofenceSimpleReports.Where(x => x.EnterTime != null && x.ExitTime != null && x.MinutesInGeofence != null).AsQueryable();
if (model.GeofenceId != -1)
{
geofenceReport = geofenceReport.Where(x => x.iGeofenceId == model.GeofenceId).AsQueryable();
}
if (model.AssetId != -1)
{
geofenceReport = geofenceReport.Where(x => x.iAssetId == model.AssetId).AsQueryable();
}
if (model.CategoryId != -1)
{
geofenceReport = geofenceReport.Where(x => x.iCategoryId == model.CategoryId).AsQueryable();
}
if (model.SiteId != -1)
{
geofenceReport = geofenceReport.Where(x => x.iSiteId == model.SiteId).AsQueryable();
}
geofenceReport = geofenceReport
.Where(x => x.EnterTime >= model.StartDateTime &&
x.EnterTime <= model.EndDateTime)
.AsQueryable();
So this is what I came up with in SQL:
I created a new type for AssetId:
USE myDatabase
GO
CREATE TYPE idTable AS TABLE (id INT)
And then in SQL:
USE myDatabase
GO
CREATE PROCEDURE [dbo].[xPT_GetGeofenceSummaryReport]
#iAssetIds idTable,
#iGeofenceId INT,
#iCategoryId INT,
#iSiteId INT,
#iAssetId INT
AS
IF #iAssetId != -1
SELECT * FROM GeofenceSimpleReport WHERE iAssetId in (#iAssetIds)
IF #iGeofenceId != -1
SELECT * FROM GeofenceSimpleReport where iGeofenceId = #iGeofenceId
IF #iCategoryId != -1
SELECT * FROM GeofenceSimpleReport where iCategoryId = #iCategoryId
IF #iSiteId != -1
SELECT * FROM GeofenceSimpleReport where iSiteId = #iSiteId
and this GeofenceSimpleReport is a database view.
But this will not work as it is logically wrong. This will 4 separate selects from the GeofenceSimpleReport.
I need to have one read from GeofenceSimpleReport with all filters applied.
And I don't want to read this data temporarily into a TABLE/LIST in memory as there is a lot of data.
Is there a way to write this query dynamically like I am doing in LINQ?

You're thinking about this procedurally, and going through a series of if-statements, rather than approaching your view as a set of data that you can filter all at once.
You can filter on the original criteria related to EntryTime, ExitTime, etc., and then for each parameter for which you provide a filterable value (not -1) then make sure the Id matches that record in the table. Anything where you gave a -1 for the value will automatically make that AND statement true.
I do this sort of thing all the time by passing in nullable parameters - if they're non-NULL then I filter on them - otherwise they just evaluate to true and pass through.
USE myDatabase
GO
CREATE PROCEDURE [dbo].[xPT_GetGeofenceSummaryReport]
#iAssetIds idTable,
#iGeofenceId INT,
#iCategoryId INT,
#iSiteId INT,
#iAssetId INT
AS
SELECT *
FROM GeofenceSimpleReport
WHERE EnterTime IS NOT NULL
AND ExitTime IS NOT NULL
AND MinutesInGeofence IS NOT NULL
AND (#iAssetId = -1 OR iAssetId IN (#iAssetIds))
AND (#iGeofenceId = -1 OR iGeofenceId = #iGeofenceId)
AND (#iCategoryId = -1 OR iCategoryId = #ICategoryId)
AND (#iSiteId = -1 OR iSiteId = #iSiteId)

Related

SQL merge multiple selects on table (trigger inserted)

I am new to the forum and am looking for help with my SQL trigger.
The trigger monitors the table tbl_adresse whether something has changed or a new data line has been added.
My SQL trigger should collect data and write it in a new table.
This works so far with this code:
CREATE TRIGGER [tgr_TEST] ON [dbo].[tbl_adresse]
AFTER INSERT, UPDATE
AS
BEGIN
MERGE [dbo].[WAWIDL_ADRESSKORREKTUR_RECHNUNGSADRESSE] AS WDL
USING (SELECT d.* FROM tbl_adresse AS d JOIN inserted AS i ON i.kAdresse = d.kAdresse) AS WWW
ON TBL.XML_tadresse_kAdresse = WWW.kAdresse
AND TBL.XML_tadresse_kKundenID = WWW.kKundenID
WHEN MATCHED
AND (
ISNULL(TBL.XML_tadresse_cFirma,0) != ISNULL(WWW.cFirma,0) OR
ISNULL(TBL.XML_tadresse_cZusatz,0) != ISNULL(WWW.cZusatz,0) OR
ISNULL(TBL.XML_tadresse_cTitel,0) != ISNULL(WWW.cTitel,0) OR
ISNULL(TBL.XML_tadresse_cVorname,0) != ISNULL(WWW.cVorname,0) OR
ISNULL(TBL.XML_tadresse_cName,0) != ISNULL(WWW.cName,0) OR
ISNULL(TBL.XML_tadresse_cStrasse,0) != ISNULL(WWW.cStrasse,0) OR
ISNULL(TBL.XML_tadresse_cPLZ,0) != ISNULL(WWW.cPLZ,0) OR
ISNULL(TBL.XML_tadresse_cOrt,0) != ISNULL(WWW.cOrt,0) OR
ISNULL(TBL.XML_tadresse_cAdressZusatz,0) != ISNULL(WWW.cAdressZusatz,0)
)
THEN
UPDATE
SET
TBL.WDL_cKundenNr = '',
TBL.WDL_cBestellNr = '',
TBL.XML_tadresse_cFirma = ISNULL(WWW.cFirma,''),
TBL.XML_tadresse_cZusatz = ISNULL(WWW.cZusatz,''),
TBL.XML_tadresse_cTitel = ISNULL(WWW.cTitel,''),
TBL.XML_tadresse_cVorname = ISNULL(WWW.cVorname,''),
TBL.XML_tadresse_cName = ISNULL(WWW.cName,''),
TBL.XML_tadresse_cStrasse = ISNULL(WWW.cStrasse,''),
TBL.XML_tadresse_cPLZ = ISNULL(WWW.cPLZ,''),
TBL.XML_tadresse_cOrt = ISNULL(WWW.cOrt,''),
TBL.XML_tadresse_cAdressZusatz = ISNULL(WWW.cAdressZusatz,'')
WHEN NOT MATCHED BY TARGET
THEN
INSERT (
XML_tadresse_kAdresse,
XML_tadresse_kKundenID,
WDL_cKundenNr,
WDL_cBestellNr,
XML_tadresse_cFirma,
XML_tadresse_cZusatz,
XML_tadresse_cTitel,
XML_tadresse_cVorname,
XML_tadresse_cName,
XML_tadresse_cStrasse,
XML_tadresse_cPLZ,
XML_tadresse_cOrt,
XML_tadresse_cAdressZusatz
)
VALUES (
WWW.kAdresse,
WWW.kKundenID,
'',
'',
ISNULL(WWW.cFirma,''),
ISNULL(WWW.cZusatz,''),
ISNULL(WWW.cTitel,''),
ISNULL(WWW.cVorname,''),
ISNULL(WWW.cName,''),
ISNULL(WWW.cStrasse,''),
ISNULL(WWW.cPLZ,''),
ISNULL(WWW.cOrt,''),
ISNULL(WWW.cAdressZusatz,'')
);
END
GO
Unfortunately I am now missing more information, which I only get from a second table called tbl_orders.
I have now tried to make another JOIN, but it does not work, I get the error message that the connection is already busy, there are probably 2 queries being made at the same time.
"Die Verbindung ist mit Ergebnissen von einem anderen hstmt belegt."
CREATE TRIGGER [tgr_TEST] ON [dbo].[tbl_adresse]
AFTER INSERT, UPDATE
AS
BEGIN
MERGE [dbo].[WAWIDL_ADRESSKORREKTUR_RECHNUNGSADRESSE] AS WDL
USING (SELECT d.* FROM tbl_adresse AS d JOIN inserted AS i ON i.kAdresse = d.kAdresse) AS WWW JOIN tbl_orders AS o ON WWW.kAdresse = o.kAdresse
ON TBL.XML_tadresse_kAdresse = WWW.kAdresse
AND TBL.XML_tadresse_kKundenID = WWW.kKundenID
WHEN MATCHED
AND (
ISNULL(TBL.XML_tadresse_cFirma,0) != ISNULL(WWW.cFirma,0) OR
ISNULL(TBL.XML_tadresse_cZusatz,0) != ISNULL(WWW.cZusatz,0) OR
ISNULL(TBL.XML_tadresse_cTitel,0) != ISNULL(WWW.cTitel,0) OR
ISNULL(TBL.XML_tadresse_cVorname,0) != ISNULL(WWW.cVorname,0) OR
ISNULL(TBL.XML_tadresse_cName,0) != ISNULL(WWW.cName,0) OR
ISNULL(TBL.XML_tadresse_cStrasse,0) != ISNULL(WWW.cStrasse,0) OR
ISNULL(TBL.XML_tadresse_cPLZ,0) != ISNULL(WWW.cPLZ,0) OR
ISNULL(TBL.XML_tadresse_cOrt,0) != ISNULL(WWW.cOrt,0) OR
ISNULL(TBL.XML_tadresse_cAdressZusatz,0) != ISNULL(WWW.cAdressZusatz,0)
)
THEN
UPDATE
SET
TBL.WDL_cKundenNr = ISNULL(WWW.cKundenNr,''),
TBL.WDL_cBestellNr = ISNULL(WWW.cBestellNr,''),
TBL.XML_tadresse_cFirma = ISNULL(WWW.cFirma,''),
TBL.XML_tadresse_cZusatz = ISNULL(WWW.cZusatz,''),
TBL.XML_tadresse_cTitel = ISNULL(WWW.cTitel,''),
TBL.XML_tadresse_cVorname = ISNULL(WWW.cVorname,''),
TBL.XML_tadresse_cName = ISNULL(WWW.cName,''),
TBL.XML_tadresse_cStrasse = ISNULL(WWW.cStrasse,''),
TBL.XML_tadresse_cPLZ = ISNULL(WWW.cPLZ,''),
TBL.XML_tadresse_cOrt = ISNULL(WWW.cOrt,''),
TBL.XML_tadresse_cAdressZusatz = ISNULL(WWW.cAdressZusatz,'')
WHEN NOT MATCHED BY TARGET
THEN
INSERT (
XML_tadresse_kAdresse,
XML_tadresse_kKundenID,
WDL_cKundenNr,
WDL_cBestellNr,
XML_tadresse_cFirma,
XML_tadresse_cZusatz,
XML_tadresse_cTitel,
XML_tadresse_cVorname,
XML_tadresse_cName,
XML_tadresse_cStrasse,
XML_tadresse_cPLZ,
XML_tadresse_cOrt,
XML_tadresse_cAdressZusatz
)
VALUES (
WWW.kAdresse,
WWW.kKundenID,
ISNULL(WWW.cKundenNr,''),
ISNULL(WWW.cBestellNr,''),
ISNULL(WWW.cFirma,''),
ISNULL(WWW.cZusatz,''),
ISNULL(WWW.cTitel,''),
ISNULL(WWW.cVorname,''),
ISNULL(WWW.cName,''),
ISNULL(WWW.cStrasse,''),
ISNULL(WWW.cPLZ,''),
ISNULL(WWW.cOrt,''),
ISNULL(WWW.cAdressZusatz,'')
);
What am I doing wrong?
Can't you add any more JOIN tables at INSERTED?
Thank You!

GL-Category Sequence in adempiere

I want to make a GL-Category Sequence like document sequence for every cash journal.
I added a field in cash journal window called journal number.
I want to generate a number for every cash journal and increment it by 1?
The document sequence is managed by the PO.java class in ADempiere. To use it, you need to add a column with the column name "DocumentNo" to your table. You will need to add the entry in the Sequence table to keep track of the numbers.
Here is the code from PO.java which is run when the record is first saved.
// Set new DocumentNo
String columnName = "DocumentNo";
int index = p_info.getColumnIndex(columnName);
if (index != -1 && p_info.getColumn(index).ColumnSQL == null)
{
String value = (String)get_Value(index);
if (value != null && value.startsWith("<") && value.endsWith(">"))
value = null;
if (value == null || value.length() == 0)
{
int dt = p_info.getColumnIndex("C_DocTypeTarget_ID");
if (dt == -1)
dt = p_info.getColumnIndex("C_DocType_ID");
if (dt != -1) // get based on Doc Type (might return null)
value = DB.getDocumentNo(get_ValueAsInt(dt), m_trxName, false, this);
if (value == null) // not overwritten by DocType and not manually entered
value = DB.getDocumentNo(getAD_Client_ID(), p_info.getTableName(), m_trxName, this);
set_ValueNoCheck(columnName, value);
}
}

SSRS Complex Dataset Filtering

I have couple of complex conditions in my stored procedure, e.g.
if #Acr != '' and #Acr != '<Select All>'
begin
delete from #temp where O_client != #Acr and O_originreason != 'RTE'
end
if #Acr = '<Select All>'
begin
delete from #temp where LEFT(O_client, 5) = 'WS80_'
AND O_client IS NULL
AND O_originreason != 'RTE'
end
if #Chnl != '' and #Chnl != '<Select All>'
begin
delete from #temp where C_Channel != #Chnl
end
and I want to get rid of it, and reimplement it in DataSet filter in reports. But I can't understand how to build such complex conditions.
Okay I did it.
I've made an expression that returns bool and compare it with true

how can i select ONLY the first row of this dbml query?

this is my original query
public UserChallenge GetUserChallenge(int userId, int challengeId)
{
var result = from userChallenge in DataContext.UserChallenges
where userChallenge.UserId == userId && userChallenge.ChallengeId == challengeId
select userChallenge;
here is the modified query
var result = from userChallenge in DataContext.UserChallenges
where userChallenge.ChallengeId == challengeId
select userChallenge;
there is more than 1 userChallenge's that hold that ChallengeId. How can I select only the first one ?
Check out FirstOrDefault.
var result = (from userChallenge in DataContext.UserChallenges
where userChallenge.UserId == userId && userChallenge.ChallengeId == challengeId
select userChallenge).FirstOrDefault();
But in the long run, it might be more helpful to determine a way to uniquely identify your records.
You can use First or FirstOrDefault to get the first item in the list. FirstOrDefault returns null if no item is found, whereas First fails with "Sequence contains no elements" error.
var result = (from userChallenge in DataContext.UserChallenges
where userChallenge.ChallengeId == challengeId
select userChallenge).FirstOrDefault();

Convert SQL - LINQ - Problem with using both Min/Max

Is there a online system which converts SQL - LINQ or can anyone else help convert the SQL - LINQ below?
SELECT MIN(startTime) As startTime, MAX(endTime) As endTime
FROM tblRA
LEFT JOIN tblA ON tblRA.asID = tblA.asID
WHERE 'xxxxxx' BETWEEN tblRA.startDate AND tblRA.endDate
AND tblA.availabilityDayOfWeek = 7
The main area I am having trouble is the .MAX/.MIN.
Heres what I have so far
public List<string> GetResourceAvailabilitiesByDate(DateTime searchDate)
{
DayOfWeek dayOfWeek = searchDate.DayOfWeek;
var minVal = from a in dc.tblResourceAvailabilities
join b in dc.tblAvailabilities on a.asID equals b.asID
where searchDate.Date >= a.startDate.Date && searchDate.Date <= a.endDate.Value.Date
&& b.availabilityDayOfWeek == (int)dayOfWeek
select b.startTime.ToShortTimeString();;
var maxVal = from a in dc.tblResourceAvailabilities
join b in dc.tblAvailabilities on a.asID equals b.asID
where searchDate.Date >= a.startDate.Date && searchDate.Date <= a.endDate.Value.Date
&& b.availabilityDayOfWeek == (int)dayOfWeek
select b.endTime.ToShortTimeString();
var min = minVal.Min(minVal.Min);
var max = maxVal.Max();
return min,max;
Thanks in advance for any help
Clare
I think your code is a little bit incorrect, and the first symptom of it is that you are using repeated code to define minval and maxval. I tried to simulate something similar to what you want and came to the following code, please adapt it to your needs.
public List<string> GetResourceAvailabilitiesByDate(DateTime searchDate)
{
DayOfWeek dayOfWeek = searchDate.DayOfWeek;
var vals = from a in dc.tblResourceAvailabilities
join b in dc.tblAvailabilities on a.asID equals b.asID
where searchDate.Date >= a.startDate.Date && searchDate.Date <= a.endDate.Value.Date
&& b.availabilityDayOfWeek == (int)dayOfWeek
select b;
var min = vals.Min(v => v.startTime).ToShortTimeString();
var max = vals.Max(v => v.startTime).ToShortTimeString();
return new List<string>() { min, max };
}
Some comments on your code, assuming it's C#.
You are trying to return an array of strings when you should be returning an array of dates.
Your where clause is pretty confuse. You're comparing the search date with startdate.Date and endDate.Value.Date. It does not make much sense.
Your select clause could select only b, or a, or whatever. You don't really need to select the date in it.