Best approach to display query with join in a search container - sql

I have a search page for books. I can search by title or by category (in my model a book is linked to a unique category). When I display the results I would like to display the category name also. Here is what I did:
<liferay-ui:search-container-results>
<%
searchContainer.setTotal(BookLocalServiceUtil.searchBooksCount(title, categoryId));
searchContainer.setResults(BookLocalServiceUtil.searchBooks(title, categoryId));
%>
</liferay-ui:search-container-results>
<liferay-ui:search-container-row
className="example.Book"
keyProperty="bookId"
modelVar="book" escapedModel="<%= true %>"
>
<portlet:renderURL var="editURL">
<portlet:param name="mvcPath" value="/html/book/edit_book.jsp" />
<portlet:param name="bookId" value="<%= String.valueOf(book.getBookId()) %>" />
</portlet:renderURL>
<liferay-ui:search-container-column-text
name="Book"
value="<%= String.valueOf(book.getTitle()) %>"
href="<%= editURL %>"
/>
<liferay-ui:search-container-column-text
name="Category"
value="<%= CategoryLocalServiceUtil.getCategory(book.getCategoryId()).getName() %>"
/>
</liferay-ui:search-container-row>
This is not optimized at all. The best way to do that would be to write a custom SQL with a join but I can't because I have optional parameters in my query (book title and category).
Any idea?
EDIT here is my current query:
public List<book> searchBooks(String title, Long categoryId)
throws SystemException {
DynamicQuery dynamicQuery = DynamicQueryFactoryUtil.forClass(Book.class);
if (Validator.isNotNull(title)) {
dynamicQuery.add(PropertyFactoryUtil.forName("title").eq(title));
}
if (Validator.isNotNull(categoryId)) {
dynamicQuery.add(PropertyFactoryUtil.forName("categoryId").eq(categoryId));
}
List<Book> lst = BookLocalServiceUtil.dynamicQuery(dynamicQuery);
return lst;
}

The easiest way to handle optional parameters is to treat the null as a non filtering value.
As you didn't say which RDBMS are using I'm showing a sample of a predicate with T-SQL syntax:
WHERE (#Title = Book.Title -- filtering
OR #Title IS NULL) -- not filtering f the parameter is null
AND ( -- chain expressions like the expression above
Please, note that this is not optimum. If you have performance problems it has to do with the way severs tretat this query: they usually are not smart enough to realize that, if the parameter is null, they don't need to evaluate the first part of the OR expression

Related

Laravel Query depend on Multiple HTML Select tags

I've multiple Select tags in HTML form i.e 'Gender', 'District' etc where the default selection is All. The eloquent query is dependent on these tags. I can retrieve data from DB if user select an option like Male or Female but don't know how to use `All'.
here is html code of Gender Select tag.
<div class="col-md-2">
<label for="gender">Gender</label>
<select wire:model="byGender" class="custom-select form-control" name="gender" id="gender">
<option selected>All</option>
<option value="male">Male</option>
<option value="female">Female</option>
<option value="combine">Combine</option>
</select>
</div>
and here is Laravel Code
public function mount()
{
$this->rows = DutySheet::where('gender', $this->byGender)->get()->toArray();
}
Note: this is Livewire function and byGender will be updated as the user select an option.
My question is what to use as value of All option in Select tag to retrieve all data from DB, "" is not working.
Your All options are represented by empty values (empty strings). You can leverage this by using the when() method on the query-builder, which effectively is an if-statement - the closure is only applied to the querybuilder if the first parameter is true.
$this->rows = DutySheet::when($this->byGender !== '', function($query) {
return $query->where('gender', $this->byGender)
})
->get()
->toArray();
You can chain these and add as many when() as you want to your query, to compute a more complex query with conditional conditionals.
You can add some logic to only apply the where condition when the select menu is set to any value other than "All".
If the user selects male, female or combine then the where condition will be run against that value, otherwise the query will return every record.
public function mount()
{
$dutySheets = DutySheet::query();
if ($this->byGender !== 'All') {
$dutySheets->where('gender', $this->byGender);
}
$this->rows = $dutySheets->get()->toArray();
}

Filter assetset by id Webcenter Sites

I need filter a assetset by id, my asset type is a flex asset. I never do this by id before and I'm stucked with this.
This is my code:
<publication:load name="pub" field="name" value='<%= ics.GetVar("site") %>'/>
<publication:get name="pub" field="id" output="siteId"/>
<%-- Content:getasset data is a custom tag to obtain attributes form a concrete asset --%>
<content:getassetdata prefix="lov" id='<%= ics.GetVar("assetid") %>' type="LOV" attributes="LOVUser"/>
<listobject:create name="powerObject" columns="power"/>
<c:forEach items="${lov.LOVUser}" var="usu">
<listobject:addrow name="powerObject"><listobject:argument name="power" value="${usu.id}"/></listobject:addrow>
</c:forEach>
<listobject:tolist name="powerObject" listvarname="powerList"/>
<%-- A this time, I have a powerList with all the IDs that I need to get --%>
<searchstate:create name="ssLovElements"/>
<searchstate:addstandardconstraint name="ssLovElements" attribute="id" list="powerList" />
<assetset:setsearchedassets name="asElementLovs" constraint="ssLovElements" assettypes="elementLOV" site='<%= ics.GetVar("siteId") %>' fixedlist="false"/>
<%-- Correct number --%>
<br/> N.Filas powerList: <ics:listget listname="powerList" fieldname="#numRows"/>
<%-- Incorrect number (Because constraint haven't effect --%>
N.Filas aslist: <ics:listget listname="aslist" fieldname="#numRows"/>
First list have 60 elements, second list have 600. I need use this constraint to extrac only wanted elements and get their attributes with multiplevalues, but I dont get working this. Any help? Thanks
I think you should use the Asset API instead of jstl tag. See the doc :
Session ses = SessionFactory.getSession();
AssetDataManager mgr = (AssetDataManager) ses.getManager(AssetDataManager.class.getName());
Condition c = ConditionFactory.createCondition( "id", OpTypeEnum.GREATER_THAN, long);
Query query = new SimpleQuery( "elementLOV", null, c, Arrays.asList( "name", ) );
query.getProperties().setIsBasicSearch( true );

Using text input to search Access number column

I have a simple search page with this text input form
<form name="assetInput" action="assetResult.jsp" method="get">
<input type="text" name="assetNo" />
<input type="submit" value="Submit" />
</form>
which takes you to a results page that will search an Access database by the Asset Number you type in the search page. The column's data type is number.
This is the code to get the input from the text box, and my attempt to convert the String to an int.
<%
String assetNumber = request.getParameter("assetNo");
int assetNum = Integer.parseInt(assetNumber);
%>
My query:
rs = stmt.executeQuery( "SELECT * FROM [Inventory Tracking] WHERE (([Inventory Tracking].AssetNumber) = '"+assetNum+"')");
I'm able to search columns from the database whose data type is text, but I keep getting errors when trying to search a number column with a String.
Thanks in advance!
Numbers do not take a delimiter, only text fields.
rs = stmt.executeQuery( "SELECT * FROM [Inventory Tracking] WHERE [Inventory Tracking].AssetNumber = "+assetNum);
You could avoid a lot of problems with a parameter.

Filtering results based on a distinct column or field value

I have an MVC 3 application running against an MS SQL 2008 database with a table named Documents. Documents are broken down by paragraph in the database. The Documents table has a DocText column containing the text of each paragraph, a DocTitle column containing the document title. My MVC 3 app has a search function that can search for a word or phrase in the DocText column or in the DocTitle column. Everything works fine except that if a particular document has the search word appearing in multiple paragraphs, my List returns multiple instances of that document. For example, if the user searches the word "Budget" and one of THE documents has the word "budget" in four different paragraphs, my returned list has that document listed four times.
What I want to achieve is to list each document that has the searched word. I only want to list the document by Title once, regardless of the number of times the search word appears in that document. The only column that is truly unique is the RecordID column, a primary key.
My controller:
public class SearchController : Controller
{
private GUICEEntities4 db = new GUICEEntities4();
//
// GET: /Search/
public ActionResult Index(string Keyword)
{
#region Keyword Search
if (!String.IsNullOrEmpty(Keyword)) {
var SearchDoc = db.Documents.Where(r => r.DocText.ToUpper().Contains(Keyword.ToUpper()) || r.Title.ToUpper().Contains(Keyword.ToUpper()) || r.DocNum.ToUpper().Contains(Keyword.ToUpper()));
ViewBag.CurrentKeyword = String.IsNullOrEmpty(Keyword) ? "" : Keyword;
return View(SearchDoc.ToList());
}
else{
return View();
}
#endregion
}
}
My View has the following:
#foreach (var item in Model) {
<tr>
<td>
<strong>AFI #Html.DisplayFor(modelItem => item.DocNum): #Html.DisplayFor(modelItem => item.Title)</strong>
<br />
#Html.DisplayFor(modelItem => item.DocSummary)
<br />
<span class="complianceitems">Number of compliance items:</span> (TBD)
</td>
<td>
<a href="/Documents/Index/#(Html.DisplayFor(modelItem => item.DocNum))">Checklist
Generator</a><br />
<a href="/UploadedDocs/#Html.DisplayFor(modelItem => item.DocFileName)" target="_blank">
Download PDF</a>
</td>
Any suggestions on how I can achieve my goal?
ADDED: Each document can be identified by the DocNum column which has a unique document number for that particular document. I've tried to iterate through the List to pull out each unqiue DocNum and then try to make that DocNum not appear again in the loop...but I was not successful.
The following SQL statement gives me the results I need. The statement assumes that the search word is "budget". I don't know how to get the same results using EF. Any suggestions?
SELECT DISTINCT DocNum, Title FROM Documents
WHERE
DocText LIKE '%budget%'
OR
Documents.Title LIKE '%budget%'
OR
DocNum LIKE '%budget%'
The issue here is in your EF query and not anything related to MVC. It's been a while since I've actively used EF but the simplest way would probably be to return just the RecordIds first.
var recordIds= db.Documents
.Where(r =>
r.DocText.ToUpper().Contains(Keyword.ToUpper()) ||
r.Title.ToUpper().Contains(Keyword.ToUpper()) ||
r.DocNum.ToUpper().Contains(Keyword.ToUpper()))
.Select(d => d.RecordId)
.Distinct();
I'm not exactly sure what you will do with each individual record from then on as there isn't enough information in your question. But this should help.
Update:
var foundDocs = new List<YourType>();
recordIds.ToList().ForEach(r => foundDocs.Add(db.TblDocLists.Single(l => l.TheDocNum == r)));
//I must point out that I'm not familiar with the latest versions of EF so this might be overkill.

Selecting items IN a row

I'm developing a website for Tenants to find properties. When they sign up, they can choose the property types that they are interested, for example: Apartment or House.
When a Tenant logs into their account, they can then do a search for properties. The search form is prepopulated with the values that they originally entered on sign up, for example: City, Postcode and so on.
The form also needs to display some checkboxes with the relevant boxes ticked for the Property Types that they selected on sign up. I'm having some problems getting this to work and wondered if there is anyone who could correct the code for me?
I believe I need to use an 'IN' statement so that the relevant checkboxes would be ticked, if the IDs for those properties are found in the CustomerReqPropertyType column. The CustomerReqPropertyType column is varchar(50) and as an example, if a user has selected Apartment and House, it is store in the row as 2, 4 (as there is a separate table with the Property Types.
This is the code I have on the page;
<%
While (NOT rspropertytype.EOF)
%>
<li>
<input type="checkbox" name="txtPropertyType" id="txtPropertyType" value="<%=(rspropertytype.Fields.Item("PropertyTypeID").Value)%>"<% If Not rstenantrequirements.EOF Or Not rstenantrequirements.BOF Then %><%If (Not isNull((rstenantrequirements.Fields.Item("CustomerReqPropertyType").Value))) Then If (CStr(rspropertytype.Fields.Item("PropertyTypeID").Value) = CStr((rstenantrequirements.Fields.Item("CustomerReqPropertyType").Value))) Then Response.Write("")%><% End If ' end Not rstenantrequirements.EOF Or NOT rstenantrequirements.BOF %> />
<label for="txtPropertyType"><%=(rspropertytype.Fields.Item("PropertyTypeTitle").Value)%></label>
</li>
<%
rspropertytype.MoveNext()
Wend
If (rspropertytype.CursorType > 0) Then
rspropertytype.MoveFirst
Else
rspropertytype.Requery
End If
%>
I would be very grateful for any help.
In order for a checkbox to be checked the checked property must equal "checked".
e.g.
<input type="checkbox" name="something" value="somethingElse" checked="checked" />
I suspect that in your code the rspropertytype and rstenantrequirements recordsets could be consolidated into one recordset generated from one SQL statement.
e.g.
SELECT pt.*
, CASE
WHEN ISNULL(tr.CustomerReqPropertyType,0) = 0 THEN 0
ELSE 1 END AS [checked]
FROM propertytype AS [pt]
LEFT JOIN tenantrequirements AS [tr]
ON pt.PropertyTypeID = tr.CustomerReqPropertyType
WHERE ...
Then your ASP code could be simplified as well.
e.g.
<%
While (NOT rs.EOF)
Dim pID : pID = rs("PropertyTypeID")
Dim pTitle : pTitle = rs("PropertyTypeTitle")
Dim checked : checked = "" : If (rs("checked") = 1) Then checked = "checked"
%>
<li>
<input type="checkbox" name="txtPropertyType" id="txtPropertyType<%=pID%>" value="<%=pID%>" checked="<%=checked%>" />
<label for="txtPropertyType<%=pID%>"><%=pTitle%></label>
</li>
<%
rs.MoveNext()
Wend
%>
This is really hard to follow. First I'd break up that line to where your while is you can just set a variable and print that to page. I assume you're trying to set the checkbox checked. What I would do is make sure the value returned isn't null assuming this is a query that just returns the property type and you left joined it with the table that has the descriptions in it when they are set for the property in question. I don't see you ever print checked to the checkbox so it's never going to be checked anyway.