Meet both WHERE criteria - T-SQL - sql-server

I need help refining the WHERE clause on a query for the table below:
Key | Name | Role | Location
111 | Bob | Manager | All Locations
222 | Jim | Manager | All Locations
333 | Tim | Sales | Washington
444 | Roy | Sales | New York
555 | Lee | Sales | All Locations
666 | Gus | Sales | All Locations
777 | Joe | Admin | All Locations
888 | Jen | Admin | New York
I need to exclude all the 'All Locations' records, but keep the 'All Locations' records where the Role is Manager. To get the desired result:
Key | Name | Role | Location
111 | Bob | Manager | All Locations
222 | Jim | Manager | All Locations
333 | Tim | Sales | Washington
444 | Roy | Sales | New York
888 | Jen | Admin | New York
I feel that the query below would exclude all the All Locations records, including the Manager ones.
SELECT * FROM Table
WHERE (Location <> 'All Locations' AND Role <> 'Manager')

You will want to expand the WHERE:
select *
from yourtable
where
(
role = 'Manager'
and location = 'All Locations'
)
or
(
location <> 'All Locations'
)
See SQL Fiddle with Demo
Returns the result:
| KEY | NAME | ROLE | LOCATION |
----------------------------------------
| 111 | Bob | Manager | All Locations |
| 222 | Jim | Manager | All Locations |
| 333 | Tim | Sales | Washington |
| 444 | Roy | Sales | New York |
| 888 | Jen | Admin | New York |

SELECT * FROM Table
WHERE (Location != 'All Locations' OR (Location = 'All Locations' AND Role = 'Manager')

You say "exclude all the 'All Locations' records, but keep the 'All Locations' records where the Role is Manager." Doesn't that mean exclude the All location records where role is not manager? i.e., don't you want records 111 and 222 to be included ??
From De Morgans Law, Not A And Not B is equivalent to Not (A Or B)
In your case , one predicate is positive and the other negative, so De Morgan would read:
Not (A And not B) <=> (Not A or B), i.e.,
That means include all records that are either Not All Locations or Manager .
If so then what you need is:
... Where Location != 'All Locations' Or Role = 'Manager'

You should use OR instead of AND
SELECT * FROM Table
WHERE (Location <> 'All Locations' OR Role = 'Manager')

Related

Track changes made in a record and get the version of the record at the given point of time in SQL Server

I need to track chages made in a record and able to get the any version of the record at given point of time.
Consider, I have the following contact table.
--------------------------
| contact |
--------------------------
| id |
| name |
| phone |
| email |
| city |
| country |
| create_by |
| created_at |
--------------------------
I want to achieve following things on the above table.
I want to track all the changes made in the records over the time.
I want to find the version of the record at the given point of time.
The original record should stay as it is (without any update).
For example,
So, I have created following table to track all the changes.
--------------------------
| contact_history |
--------------------------
| contact_id |
| field_name |
| old_value |
| new_value |
| modified_by |
| modified_at |
--------------------------
With this data model,
To create a new contact record, we will create the record in the contact table.
To Update a record, we will create a new record in the contact_history record with the field name, new value, current time and who modified the record.
In this way I can able to track, what change was made and who made the change and the same time the original record will stay as it is without any change.
What I am trying to achieve is to find the version of all the contact records at a given point of time.
For example, consider the following record.
Contact table
------------------------------------------------------------------------------------------------
| id | name | phone | email | city | country | created_by | created_at |
------------------------------------------------------------------------------------------------
| 1 | Steve | 1111111 | steve#abc.com | NY | USA | John | 2019-04-01 13:17:49.417 |
------------------------------------------------------------------------------------------------
Each update will be created as a history record in the contact_history table.
contact_history
-------------------------------------------------------------------------------------------------------
| contact_id | field_name | old_value | new_value | modified_at | modified_by |
-------------------------------------------------------------------------------------------------------
| 1 | email | steve#abc.com | steve#changed.com | 2019-04-02 08:19:49.213 | Arnold |
| 2 | city | NY | LA | 2019-04-03 12:48:37.568 | John |
| 3 | city | LA | SF | 2019-04-04 25:25:19.715 | John |
-------------------------------------------------------------------------------------------------------
When I need the version of the contact record before 2019-04-02 I should able to get the following,
------------------------------------------------------------------------------------------------
| id | name | phone | email | city | country | created_by | created_at |
------------------------------------------------------------------------------------------------
| 1 | Steve | 1111111 | steve#abc.com | NY | USA | John | 2019-04-01 13:17:49.417 |
------------------------------------------------------------------------------------------------
When I need the version of the contact record before 2019-04-03 I should able to get the following,
----------------------------------------------------------------------------------------------------
| id | name | phone | email | city | country | created_by | created_at |
----------------------------------------------------------------------------------------------------
| 1 | Steve | 1111111 | steve#changed.com | NY | USA | John | 2019-04-01 13:17:49.417 |
----------------------------------------------------------------------------------------------------
When I wanted the latest version of the same record I should able to get,
----------------------------------------------------------------------------------------------------
| id | name | phone | email | city | country | created_by | created_at |
----------------------------------------------------------------------------------------------------
| 1 | Steve | 1111111 | steve#changed.com | SF | USA | John | 2019-04-01 13:17:49.417 |
----------------------------------------------------------------------------------------------------
The example is given for only one record. It can be applicable for multiple contact records.
How can I write a efficient query to achieve this in SQL Server.
Simple. Use a TOP 1 query to get the most recent record before the date you want to filter on.
Unfortunately, due to the data model you've chosen to use, you'll need to do a TOP 1 subquery for every field in your result set that can be in your history table.
SELECT id,
(SELECT TOP 1 new_value ... WHERE field_name='Name' ... ) AS Name,
etc...

Delete partial dulicate rows - sql

I have some troubles with deleting partial duplicate rows
The structure is like this:
+-----+--------+--+-----------+--+------+
| id | userid | | location | | week |
+-----+--------+--+-----------+--+------+
| 1 | 001 | | amsterdam | | 11 |
| 2 | 001 | | amsterdam | | 23 |
| 3 | 002 | | berlin | | 28 |
| 4 | 002 | | berlin | | 22 |
| 5 | 003 | | paris | | 19 |
| 6 | 003 | | paris | | 35 |
+-----+--------+--+-----------+--+------+
I only need to keep one row from each userid, it doesn't matter which week number it has.
Thanks,
Maxcim
This should work across most databases:
DELETE
FROM yourTable
WHERE id <> (SELECT MIN(id)
FROM yourTable t
WHERE t.userid = userid)
This query would delete from each userid group all records except for the record having the lowest id for that group. I assume that id is a unique column.
This method is tested, try it.
We are getting the number of rows occuring at each record, and then we are deleting only the ones with more than 1 row occruring... keeping the original one.
BEGIN TRANSACTION
SELECT UserID, Location,
RN = ROW_NUMBER()OVER(PARTITION BY UserID, Location ORDER BY UserID, Location)
into #test1
FROM dbo.MyTbl
Delete MyTbl
From MyTbll
INNER JOIN #test1
ON #test1.UserID= MyTbl.UserID
WHERE RN > 1
if ##Error <> 0 GOTO Errlbl
Commit Transaction
RETURN
Errlbl:
RollBack Transaction
GO

SQL Server: Count grouping by user and date

In my SQL Server 2008 i got a table that stores datetime of every users' actions. It looks something like this:
id | username | action | actionDate
------------------------------------
1 | bob | add | 2015-08-15 11:20:12
2 | bob | add | 2015-08-15 11:21:52
3 | sandra | add | 2015-08-15 11:25:32
4 | sandra | add | 2015-08-15 11:26:32
5 | bob | add | 2015-08-15 11:31:52
6 | sandra | add | 2015-08-16 13:46:32
7 | sandra | add | 2015-08-16 13:26:32
8 | bob | add | 2015-08-16 13:31:52
9 | sandra | add | 2015-08-16 13:46:32
This table rather big and stores data for many-many days. So i need to get how many times each user made action "add" for every day. e.g.:
actionDate | username | countRow
2015-08-15 | bob | 3
2015-08-15 | sandra | 2
2015-08-16 | bob | 2
2015-08-16 | sandra | 3
I've tried a lot of different queries, but I still can't get it. The closest query I think looks like this:
SELECT S.username, S.actionDate, C.countRow
From dbo.actionTable S
INNER JOIN( SELECT Convert(date, actionDate),count(username) as countRow
FROM dbo.actionTable
WHERE action = 'add'
GROUP BY Convert(date, actionDate)) C ON S.actionDate = C.actionDate
but this query returns me too much wrong data. Please, tell me where I'm wrong.
Why don't do it directly ..
select
username
,convert(date,actionDate) as actionDate
,count(*) as countRow
from actionTable
where action = 'add'
group by username
,convert(date,actionDate)
SELECT S.username, Convert(date, S.actionDate), count(S.id) as countRow,S.action
From dbo.actionTable S WHERE S.action = 'add'
GROUP BY Convert(date, S.actionDate),S.action,S.username
Try
select convert(date,actionDate) actionDate, username,
count(*) coutntRow from actionTable
where action = 'add'
group by convert(date,actionDate), userName
I recommend you the normalization of your database.
If I were you I do this:
++++++++++++++++++++++++
Table name: **userTable**
------------------------------------
id | username
------------------------------------
1 | bob
2 | sandra
3 | peter
++++++++++++++++++++++++
Table name: **actionTable**
------------------------------------
id | action
------------------------------------
1 | add
2 | update
3 | delete
++++++++++++++++++++++++
Table name: **actionUser**
------------------------------------
ID | user_id | action_id | actionDate
------------------------------------
| 1 | 1 | 1 | 2015-08-15 11:20:12
| 2 | 2 | 2 | 2015-08-15 11:21:52
| 3 | 1 | 1 | 2015-08-15 11:25:32
This is a better architecture for this problem.
And the query should be like this:
SELECT COUNT(user_id)
FROM dbo.actionUser
WHERE user_id = %
where % is the ID of your user.

SQL Server - tricky query to update contact id using ROW_NUMBER to reference index value

A previous developer used an index rather than the actual contactID to reference which of the associated contacts are the primary contact. The index works well when the app gets the contacts and sets the primary contact in the list on the page, but try joining for a report! Not easy; so I want to update the main table with the actual contact ID to make for a simple join and to avoid this buggary.
In this particular case, I need to update tblInquiry with the claimantContactID and agentContactID. Those two fields I just created and defaulted to 0. However, the challenge is to use the claimantContactIndex and agentContactIndex values from tblInquiry, to get the respective nth row from tblContacts. The index is 0 based, so if the index value is 2, then get the ID of the 3rd contact, for example.
Also, claimantContactIndex and agentContactIndex can either be NULL or some number. If NULL, then assume the first contact (index 0).
I will also add that the contacts index cannot have an order by on it because the application relies upon the natural order when getting the contacts list (there is no order by in the stored procedure), and selects then the index accordingly.
DB Platform: SQL Server 2008 R2 Express Edition.
I have the following table structure:
tblInquiry
id | claimantID | agentID | claimantContactIndex | agentContactIndex | claimantContactID | agentContactID
--------------------------------
1 | 1001 | 2001 | 2 | 0 | 0 | 0
2 | 1002 | NULL | 0 | NULL | 0 | 0
tblClaimant
id | name | address | phone | email
--------------------------------
1001 | Widgets Inc. | 123 W. Main | 5550000 | widgets#here.com
1002 | Thingies LLC. | 456 W. Main | 5551111 | thingies#here.com
tblAgent
id | name | address | phone | email
--------------------------------
2001 | Simon Bros. | 789 W. Main | 5552222 | simon#here.com
tblContacts
id | claimantID | agentID | fn | ln | phone | email
--------------------------------
3001 | 1001 | NULL | John | Doe | 5553333 | john#here.com
3002 | 1001 | NULL | Fred | Flynn | 5554444 | fred#here.com
3003 | 1001 | NULL | Mike | Brown | 55555555 | mike#here.com
3004 | 1001 | NULL | Susan | Pierce | 5556666 | susan#here.com
3005 | NULL | 2001 | Jeff | Bridges | 5557777 | jeff#here.com
3006 | NULL | 2001 | Karry | Sinclair | 5558888 | Karry#here.com
3007 | NULL | 2001 | Steve | Green | 5559999 | steve#here.com
3008 | NULL | 2001 | Peter | White | 5550001 | peter#here.com
Update:
I have worked out the select part of this solution and I can now get the correct claimant contact info using ROW_NUMBER() and a JOIN. I will add more to get correct agent contact info. I also handled the case where an index is NULL. And ultimately I will work this out to update the inquiry table now that I have the right contactID.
SELECT
i.id inquiryID, i.claimantContactIndex, i.agentContactIndex, i.claimantContactID, i.agentContactID
,r.id contactID, r.claimantID, r.agentID
,r.*
FROM
(
SELECT ROW_NUMBER()
OVER (Partition by con.claimantid Order by (SELECT NULL)) AS RowNumber, *
FROM tblContacts con
) r
INNER JOIN
tblInquiry i on i.claimantid = r.claimantid and ((isnull(i.claimantContactIndex, 0) + 1 = r.RowNumber ))
WHERE
i.id in (1, 2, 3, 4, 5)
ORDER BY
i.id
This issue was resolved by doing the following:
As I posted above, using ROW_NUMBER() and (SELECT NULL()) along with an isnull to handle null values to get the correct contacts.
I selected the results into a temp table.
I then updated the inquiry table by joining it to the temp table.
dropped temp table
I had to do this in two passes, once for claimants, a second time for agents.
Thx #EricH for pointing me in the right direction.
You could do something like:
Using ideas from here:
https://msdn.microsoft.com/en-us/library/ms186734.aspx
SELECT
ROW_NUMBER() OVER (Order by Id) AS RowNumber,
claimantID, agentID, (etc...)
FROM
tblContacts
To get an index based resultset. I'd drop it into a temp table and select from that where RowNumber = Whatever index you want.

vb.net Comparing 2 Databases

I have Database1 and Database2, i add each of them to a datatable object.
now Database1 is changed through Access, Records maybe added removed or row data might change.
so the database Looks like
+----+----------+-------+-------+
| ID | Name | Price | Sales |
+----+----------+-------+-------+
| 1 | ProductA | 453 | 55 |
| 2 | ProductB | 43 | 156 |
| 3 | ProductC | 22 | 161 |
+----+----------+-------+-------+
so if i Delete the row with Product ID=1 i want it to be deleted in the second Database2
if i add new product with ID = 4 i want it to be Added to Database2, also if i change Price or Sales i want it to change in Database2 for that record.
now the problem is the Database records are not in the same order in both databases so looping might take alot of time..for example if ID=4000 was removed than i've to loop through the whole Database to find this out.
so are thre anyother solutions than alot of loops?
It is possible to refer to another database in SQL run against an MS Access connection:
SELECT t1.*, t2.* FROM Table1 t1
INNER JOIN [;DATABASE=Z:\Docs\Test.accdb].Table1 t2
ON t1.ID=t2.ID
From here, it is easy enough to create queries to find missing or changed records.
If ID is the identifier for the row, then I do not think you can safely do what you are asking.
Given the example above for Table 1
+----+----------+-------+-------+
| ID | Name | Price | Sales |
+----+----------+-------+-------+
| 1 | ProductA | 453 | 55 |
| 2 | ProductB | 43 | 156 |
| 3 | ProductC | 22 | 161 |
+----+----------+-------+-------+
And simulating the out of order condition for Table 2
+----+----------+-------+-------+
| ID | Name | Price | Sales |
+----+----------+-------+-------+
| 1 | ProductB | 43 | 156 |
| 2 | ProductA | 453 | 55 |
| 3 | ProductC | 22 | 161 |
+----+----------+-------+-------+
If you delete ID 2 from table 2, you will end up deleting Product B from Table 1 (not product A). I don't think this is what you want.
Are you sure that ID is the primary key for these values?

Resources