SQL Server WHERE clause with AND or OR - sql-server

I have below search form which calls a stored procedure. Client requested a new feature which he needs to Search Product OR Items. To satisfy this new requirement I added a checkbox as in the image. If user check this checkbox, query should return either Products OR Items.
This is the existing query I used for the search,
Select * FROM PRODUCT P INNER JOIN ITEM I ON
P.ID = I.PID
WHERE
(#para_product_country is NULL OR #para_product_country = P.Country)
AND
(#para_product_city is NULL OR #para_product_city = P.City)
AND
(#para_product_street is NULL OR #para_product_street = P.Street)
AND
(#para_item_country is NULL OR #para_item_country = I.Country)
AND
(#para_item_city is NULL OR #para_item_city = I.City)
AND
(#para_item_street is NULL OR #para_item_street = I.Street)
How can I implement the query depending on users selection of checkbox which needs to search Products OR Items ? If user check the checkbox, query should return data either from Product OR Item. If user did not select the checkbox query should return data from Product AND Item.
I would like to know how to change the WHERE condition AND or OR according to checkbox selection ?

Related

Update changes to related tables in VB.Net

I have two related SQL tables, both of which I open with a dataadapter and fill into a dataset. I set the relationship as follows:
DS.Relations.Add("RBT", DS.Tables("Jobs").Columns("ID"), DS.Tables("BillTech").Columns("JobID"), False)
Dim BSBT As New BindingSource
BSBT.DataSource = BS
BSBT.DataMember = "RBT"
The ID column in the Jobs SQL table is an identity seed incremented by 1.
The columns from the Jobs table are displayed on a form with a binding navigator to move from job to job. The related columns from the BillTech table are displayed in a datagridview on the Jobs form.
If the user adds a row to the datagridview (i.e. a new row to the BillTech table) for an existing job, I put the ID from the selected job into the JobID column of the datagridview in the DefaultValuesNeeded event of the datagridview. That all works great.
The problem is when the user adds a new job to the Jobs table and then tries to add a new row in the datagridview for that new job. Since the ID of that new job is unknown (since it hasn't been updated back to the SQL table), I use the dataadapter to update the Jobs table and then retrieve the assigned ID from the updated SQL table using the "GetNewJobID" function. I then try to insert that value in the new row of the datagridview. See the code below:
Private Sub DataGridView2_DefaultValuesNeeded(sender As Object, e As DataGridViewRowEventArgs) Handles DataGridView2.DefaultValuesNeeded
Dim JobID As Integer = 0
With e.Row
Dim DR() As DataRow = DS.Tables("Jobs").Select("Name = '" & Replace(Me.JobName.Text, "'", "''") & "'")
If DR.Length = 1 Then
JobID = DR(0).Item("ID")
Else
Dim Name As String = Me.JobName.Text
BS.EndEdit()
DA.InsertCommand = CB.GetInsertCommand
DA.Update(DS.Tables("Jobs"))
'Because we have already added this job to the database, we keep a list so we can see if the user wants this job added to QB.
If NewJobs.Contains(Name) = False Then
NewJobs.Add(Name)
End If
JobID = GetNewJobID(Name)
End If
.Cells("JobID").Value = JobID
End With
End Sub
I get an error on the next to last line of the above sub ".Cells("JobID").Value = JobID saying that the column "JobID" does not exist. Since this only occurs when adding a BillTech row to a new Job Row, I'm guessing that by updating the Jobs SQL table, this somehow breaks the connection to the datagridview?
How can I update this properly? I've looked at TableAdapterManager, but this seems to only work with typed datasets. Because these SQL tables are on a Windows Server 2003 server, I cannot bring them in with an "Add New Datasource" wizard.
I'll pick on the typical parent/child or master/detail of Customers:Orders. If you were using an access or sql server db with a relationship defined in the db and you made a new dataset, opened it in the designer, right clicked the surface and chose Add TableAdapter, put SELECT * FROM customers and repeated the process (from right click..) for Orders you would end up with a Customers DataTable and TableAdapter, an Orders DataTable and TableAdapter and a DataRelation between the two linking (say) orders.customerid to customers.id
Save the set, then take a look in the data sources window and expand every node.
There is a top level node of Customers and a top level node of Orders, and you'll also notice an Orders node that is a child of Customer
Drag the Customers node out of datasources, onto a new form. A customersdatagridview, dataset, customerstableadapter, customersbindingsource and customersbindingnavigator appear. Delete the navigator (for clarity right now). You will note that the customersdatagridview is bound to the customersbindingsource and the customersbindingsource is bound to the Customers table of the dataset
Drag the top level Orders out of the datasources window onto the form. You'll notice that an ordersdatagridview, ordersbindingsource, orderstableadapter and ordersnavigator appear. Delete the navigator. Note that, like before, the ordersdatagridvew binds to the ordersbindingsource and the ordersbindigsource binds to Orders in the dataset. This is what I think you've done
Delete everything that appeared when you dragged Orders out (dgv/bs/ta for orders). Don't delete the dataset - it's still in use by hings named customers*
Now go back to the datasources window and this time drag the child Orders out that is below the Customers node. The same components appear (ordersdgv/bs/ta/nav). Delete the nav. Look at the ordersbindingsource datasource and datamember properties this time. You'll notice that unlike last time, this ordersbindingsource is not bound to the dataset directly but to the customersbindingsource, specifically to a datamember named after the same name as the datarelation in the set
In this setup, when the parent current row changes in the customersbindingsource, the ordersbindingsource will only see a filtered set of orders rows - the filter passes only rows whose orders.customerid is equal to the current id in th customersbindingsource
Note; it's important that the Orders data has to be in the dataset. Nothing here automagivally downloads database data. If you fill customers but don't fill the orders data then no data will show in the orders, no matter how it is bound.
The simplistic approach takes the default queries in the tableadapters (select * from customers, select * from orders) and dwnloads the ENTIRE db into the dataset. It'll work for demonstration purposes but you really don't want to do that in a production program.
Go back to the dataset and alter the default queries in the table adapters to be SELECT * FROM customers WHERE id = #id and the corollorary for orders. Then add ANOTHER query to the customers TA (right click it and choose add query):
SELECT * FROM customers WHERE lastname = #lastname
Call this query FillByLastName (the wizard will ask you to name it and suggest FillBy. Don't accept the default; give it a sensible name)). This might load 10 customers.
Now go to the ORDERS tableadapter and add another query to that too:
SELECT * FROM orders WHERE customerid = #customerid
Call it FillByCustomerId. This can be used, once we have loaded 10 customers, to retrieve the orders for those 10 customers:
'fill the form dataset with customers named smith:
Me.someDataSet.Clear()
customersTableAdapter.FillByLastName(someDataSet, "Smith") 'it will fill the Customers table with Smiths
ordersTableAdapter.ClearBeforeFill = false 'turn this off or every call to fill will remove existing order from the datatable
For Each cro as CustomersRow in someDataSet.Customers 'for all our smiths
ordersTableAdapter.FillByCUstomerId(someDataSet, cro.Id) 'fill orders for customer with that id
Next cro
So now you have 10 customers, and maybe 50+ orders - you don't have the whole DB in your dataset, just the interesting data. Databinding via the datarelation exposed on the customers bindingsource will take care of showing only the related rows. Click on various rows in the customers datagridview and note that the orders shown in the ordersdatagridview changes to show only the relevant rows
It is intended that you add as many queries to a tableadapter as suits your needs. You could, rather than looping the customers and filling their orders by each customer ID, write a query that returns them all in one hit, on the ORDERS tableadapter:
SELECT orders.*
FROM
orders INNER JOIN customers on orders.customerid = customers.id
WHERE
customers.lastname = #lastName
The query selects only data from orders, but joins through to customers and searches on customer last name, so we should call this FillByCustomerLastName
Our code could then look like:
'fill the form dataset with customers named smith:
Me.someDataSet.Clear()
customersTableAdapter.FillByLastName(someDataSet, "Smith") 'it will fill the Customers table with Smiths
ordersTableAdapter.FillByCustomerLastName(someDataSet, "Smith") 'fill orders for all customers with a last name of smith
Horses for courses which you choose. I tend to pick the first approach and loop because it's more flexible, but where outright performance matters it can be faster to use a pattern like the second

Return Count if linked table does not contain specific value

I am linking two tables in Microsoft SQL Server. The one table contains documents and the other contains the event status, which I need to specify a condition.
On the documents table, I am looking at the document code which is linked to the event, for example 371268-INV-1 and 371268-INV-1-APPROVED. There should be 2 documents per event.
I need to return values/ counts where the status from the Events table is approved but where there is no document code containing Approved.
I started out using:
select * from Documents
join EVENTS on event_code = left (document_code, 6)
where document_code like '371268%' and Event_Status = 'Approved'
This will get all events that are approved that do not have 2 records in the documents table. I think this will get you the results you are looking for.
select *
from events
where event_status = 'approved'
and event_code not in(select left (document_code, 6)
from documents
group by left (document_code, 6)
having count <>2)
If I correctly understand, this is what you need
select * from Documents
join EVENTS on event_code = left (document_code, 6)
WHERE
EVENTS.Event_Status = 'Approved' AND Documents.document_code NOT LIKE '%APPROVED';

Access to SQL Server - query results from a table as another tables query columns

I am taking user input from a series of combo boxes in a MS Access form, which might not all be chosen, so some will be "". But for the responses that are not "", I want to query those columns for the table the user has selected.
For example, this is my utopian solution which I'm I have no idea how to accomplish other than building a query for every possible combination and calling a procedure for that query:
SELECT **NON "" COMBOBOX CHOICES**
FROM T1
You can talk about the combobox field in the following syntax:
Forms![myForm]![myComboBox1Name]
The above returns the text from that box, either "" or a string they chose from the options. So in short, I was wondering if I inserted the valid non "" strings from those combo boxes into a table, then somehow used a SELECT statement on the table we could use the rows returned as the fields I want to query, example:
SELECT (SELECT * FROM ValidTable)
FROM T1
If the resource from the following link were successful, https://www.google.com/amp/s/blog.sqlauthority.com/2012/10/27/sql-server-storing-variable-values-in-temporary-array-or-temporary-list/amp/

TSQL query to filter directory

I'm trying to create a business directory in which I'm using the following query to pull data from 2 tables that contain the business info.
select *
from BND_Listing
left join BND_ListingCategories on BND_Listing.CatID = BND_ListingCategories.CatID
order by Company asc
I have a form that has 3 dropdowns I'm using to filter the above query using "Filters" that really are just components I need to add to my query above that will listen to query string values passed in by the form.
On submit of my form I'm redirecting back to the same URL but adding the following in my URL based on values selected from 3 dropdown fields.
filter-Category=[Category]&filter-City=[City]&filter-State=[State]
I've got this working correctly but am having difficulties when no value is passed into my URL. This happens when a user filters only by 1 of the 3 possible fields. To fix this I'm thinking I can create an "All" value that would be like filter-State=ALL
How can I update my query to pull data to listen for these filters in the query-string?
Any insight, examples really appreciated.
Hope I make sense I'm still new to programming.
The following query returns 0 results until all filters are set. If only 1 filter is set it crashed my application.
select *
from BND_Listing
where
(Category = '[querystring:filter-Category]'
or '[querystring:filter-Category]'='All')
and
(City = '[querystring:filter-City]'
or '[querystring:filter-City]'='All')
and
(State = '[querystring:filter-State]'
or '[querystring:filter-State]'='All')
UPDATE:
Thanks for all the input everyone.
I've tried this simplified query in SQL Server Management Studio to test.
SELECT *
FROM BND_listing
WHERE city = IsNull('Trinity', city)
It returns no results even though 'Trinity' is in fact a city in one of my records in the BND_Listing table.
I understand the ALL would add more filters but this basic query is still not pulling anything?
UPDATE 2:
On page load where I have not pressed the sort button and there are no query string values passed yet. If I want my grid to load ALL table records should I use a UNION command for my basic query.
select *
from BND_Listing
Plus the more complex query used for filtering the results? So far all query examples below pull in nothing from my grid because of the WHERE statement.
Are you limited to just a select query that has to be placed in the plug-in? If not, I would create a stored procedure and read up on dynamic SQL. Dynamic SQL would allow you to dynamically generate and execute a completely different query based on whatever conditions you specify. With dynamic SQL, you could also dynamically generate the entire predicate instead of having to hard code each condition.
Another (less efficient) alternative would be to use LIKE instead of = in your predicate. For example:
SELECT *
FROM BND_Listing
WHERE Category LIKE CASE
WHEN [querystring:filter-Category] = 'All' THEN '%'
ELSE '[querystring:filter-Category]'
END
AND City LIKE CASE
WHEN [querystring:filter-City] = 'All' THEN '%'
ELSE '[querystring:filter-City]'
END
AND State LIKE CASE
WHEN [querystring:filter-State] = 'All' THEN '%'
ELSE '[querystring:filter-State]'
END
Assuming you want to search for 'All' for a given category when no filter is present, you can just treat an empty filter as meaning all:
SELECT *
FROM BND_Listing
WHERE (Category = '[querystring:filter-Category]' OR
'[querystring:filter-Category]' = 'All' OR
COALESCE([querystring:filter-Category], '') = '') AND
(City = ... )
...
Perhaps you could try something like this.
SELECT *
FROM BND_listing
WHERE category = IsNull('[querystring:filter-Category]', category)
AND city = IsNull('[querystring:filter-City]', city)
AND state = IsNull('[querystring:filter-State]', state)
This functionality will check for an active filter if present and compare the appropriate field to ensure it matches.
In the case the filter has not been set it will compare the field to itself so it will always return a true result.
When you want all the records when the input is NULL then handle it using IS NULL.
SELECT *
FROM BND_listing
WHERE (category = '[querystring:filter-Category]' OR [querystring:filter-Category]' is NULL)
AND (city = '[querystring:filter-City]' OR '[querystring:filter-City]' IS NULL)
AND (state ='[querystring:filter-State]' OR '[querystring:filter-State]' IS NULL)
Note : This method will use any INDEX present on Category or city or state where as ISNULL or COALESCE method will restrict the optimizer from using INDEX

Combining SQL results using LINQ

I have a database of company registrants (for a search/directory functionality). We've added a new table to hold "enhanced" information for registrants that pay for this feature (such as advertisements/additional images/logos etc). Right now the new table just holds the registrants unique identifier, and a few additional fields (paths to images etc). A user can search for users with specific criteria, and the enhanced listings should appear at the top of the list. The results should not show any registrant twice (so if a user has an enhanced listing they should only appear in the top "enhanced listing" area). How can I accomplish this?
Left outer join from the old table to the new table.
Prepend to your query's "order by" "case when new_table.id is null then 1 else 0 end"
So if you had this:
select foo, bar from old_table
order by bar, foo;
You'd have this:
select a.foo, a.bar from old_table a
left join new table b on (a.customer_id = b.customer_id)
order by
case when new_table.customer_id is null then 1 else 0 end,
bar, foo;
Edit: I left out the "left" from the outer join in the code.
If you are using LINQtoSQL and the designer-generated entities, you should have an entity set of related information on your registrant entity -- assuming you have set up the proper foreign key relationship. If you added this later you may need to add this by hand (see here) or delete/re-add your entities to the designer for it to pick up the new relationship. Then your query would be something like:
var registrants = db.Registrants.Where( ... selection criteria here ... );
registrants = registrants.OrderByDescending( r => r.EnhancedData.Count() )
.ThenBy( r => r.Name ); // or normal sort order
Presumably count will be either 0 or 1 so this should put the ones with enhanced data at the top of your result.

Resources