I want to update values in column, based on condition that need to compare data from another table - sql

I need help on one case in SQL, so I have to fill one column DIFFERENCE with 'Above' or 'Below' in table CLIENTS, if the date in other column in table - DOCUMENT is above or below 4 months from now. I tried with this
UPDATE CLIENTS
SET DIFFERENCE = CASE WHEN MONTHS_BETWEEN(TO_DATE((SELECT DATA FROM DOCUMENT, CLIENTS WHERE DOCUMENT.ID_CLIENT=CLIENTS.ID_CLIENT ),'DD.MM.YYYY'),TO_DATE(SYSDATE,'DD.MM.YYYY')) < 4 THEN 'Below' ELSE 'Above' END
but it returns lot of values, so I tried to JOIN the tables and
UPDATE CLIENTS
SET DIFFERENCE = CASE WHEN MONTHS_BETWEEN(TO_DATE(DATA,'DD.MM.YYYY'),TO_DATE(SYSDATE,'DD.MM.YYYY')) < 4 THEN 'Below' ELSE 'Above' END
FROM CLIENTS JOIN DOCUMENT
ON DOCUMENT.ID_CLIENT=CLIENTS.ID_CLIENT
but this time says Not properly ended.
I'm working with Oracle db.
Please if you see the answer, write me!
Thank you in advance!
SELECT CLIENTS.ID_CLIENT,MIN(DOCUMENT.DATA) AS "DATA"
FROM DOCUMENT,CLIENTS
WHERE CLIENTS.ID_CLIENT=DOCUMENT.ID_CLIENT
GROUP BY CLIENTS.ID_CLIENT
and some of the results:
ID_CLIENT DATA
54 01/23/2014
57 01/23/2014
78 01/23/2014
87 01/24/2014
91 01/24/2014
I found the solution,
UPDATE CLIENTS
SET DIFFERENCE = CASE WHEN MONTHS_BETWEEN(TO_DATE((SELECT MIN(DATA) FROM DOCUMENT, CLIENTS WHERE DOCUMENT.ID_CLIENT=CLIENTS.ID_CLIENT),'MM.DD.YYYY'),TO_DATE(SYSDATE,'MM.DD.YYYY')) < 4 THEN 'Below' ELSE 'Above' END
The mistake was 'MM.DD.YYYY' ... first I used 'DD.MM.YYYY' - very stupid mistake!
Thanks for all the answers! ekad YOU really helped me!!!

Instead of joining the tables, you need to check whether there's any related documents with DATA more than 4 months from now using EXISTS. It also seems that DOCUMENT.DATA is a varchar and the value is set using mm/dd/yyyy format, so you need to change the second parameter of TO_DATE function to MM/DD/YYYY
UPDATE CLIENTS
SET DIFFERENCE = CASE WHEN EXISTS
(SELECT 1 FROM DOCUMENT
WHERE ID_CLIENT = CLIENTS.ID_CLIENT
AND MONTHS_BETWEEN(TO_DATE(DATA,'MM/DD/YYYY'),SYSDATE) > 4)
THEN 'Above'
ELSE 'Below' END

Related

First Contact Resolution

I am using Microsoft SQL Server Management Studio
I have a table which contains a unique customerId, date when the contact was made and reason why the contact was made.
customerId
,DateOfContact
,ContactReason
I need to create two Yes (Y) or No (N) columns.
Column 1 named 7DayContact
Column 2 named 7DaySameContact
Column 1 should provide me with a Y or N if the same customerId had another contact in the previous 7 days (interval of 7 days)
Column 2 should provide me with a Y or N if the same customerId had another contact in the previous 7 days with the same contactReason.
How should I go about it?
I didn't manage to do anything.
I am using Microsoft SQL Server Management Studio.
What I did for the first scenario is the below query, however, all results are showing as 'N' whilst there are results that should show as 'Y'.
Basically, I want to look at the con.CustomerId, go back 7 days and check whether the same con.CustomerId shows up. If the same con.CustomerID shows up, then give 'Y' else 'N'.
SELECT
con.[CustomerID]
,con.[ContactDate]
,con.[ContactReason1]
,con.[ContactReason2]
,con.[ContactReason3]
,CASE
WHEN LAG(con.[ContactDate], 1) OVER (PARTITION BY con.[CustomerID] ORDER BY con.[ContactDate]) BETWEEN con.[ContactDate] AND DATEADD(DAY, -7, con.[ContactDate])
THEN 'Y' ELSE 'N'
END AS '7DayContact'
FROM [DWH_Unknown1].[unknown2].[unknown3] con
Order By disp.DispositionDate DESC
For the second scenario I want to look at the con.CustomerId and con.ContactReason2, go back 7 days and check whether the same con.CustomerId having the same con.ContactReason2 shows up. If the same con.CustomerID having the same con.ContactReason2 shows up, then give 'Y' else 'N'.
Please note that you have two different tags mysql <> sql-server.
I used SQL server coding, best to use the LAG function:
SELECT customerId, DateOfContact, ContactReason,
CASE WHEN LAG(DateOfContact, 1) OVER (PARTITION BY customerId ORDER BY DateOfContact) BETWEEN DateOfContact - INTERVAL 7 DAY AND DateOfContact THEN 'Y' ELSE 'N' END AS 7DayContact,
CASE WHEN LAG(ContactReason, 1) OVER (PARTITION BY customerId ORDER BY DateOfContact) = ContactReason THEN 'Y' ELSE 'N' END AS 7DaySameContact
FROM yourTable

Improve CASE WHEN Performance

I want to calculate customer retention week over week. My sales_orders table has columns order_date, and customer_name. Basically I want to check if a customer in this week also had an order the previous week. To do this, I have used CASE WHEN and subquery as follows (I have extracted order_week in a cte I've called weekly_customers and gotten distinct customer names within each week):
SELECT wc.order_week,
wc.customer,
CASE
WHEN wc.customer IN (
SELECT sq.customer
FROM weekly_customers sq
WHERE sq.order_week = (wc.order_week - 1))
THEN 'YES'
ELSE 'NO'
END AS present_in_previous_week
from weekly_customers wc
The query returns the correct data. My issue, the table is really huge with about 15000 distinct weekly values. This obviously leads to very long execution time. Is there a way I can improve this loop or even an alternative to the loop altogether?
Something like this:
SELECT
wc.order_week,
wc.customer,
CASE WHEN wcb.customer IS NOT NULL THEN "YES" ELSE "NO" END AS present_in_previous_week
FROM weekly_customers AS wca
LEFT JOIN
weekly_customers AS wcb
ON
wca.customer = wcb.customer
AND wca.order_week - 1 = wcb.order_week
This joins all of the customer data onto the customer data from a week ago. If there is a record for a week ago then wcb.customer will not be null, and we can set the flag to "YES". Otherwise, we set the flag to "NO".

WHERE conditions being listed in a column if they are met

I have a file that i receive each morning which contains details of customers whos information doesnt meet certain criteria, i have built a script with many WHERE conditions that, if met, will show customers information and put them in a file but im having trouble finding out why they are wrong.
As i have many conditions in the where clause, is there a way to show which column has the incorrect information
For example i could have a table like this:
NAME|ADDRESS |PHONE|COUNTRY
John|123avenue |12345|UK
My conditions could be
SELECT * FROM CUSTOMERS
WHERE NAME LIKE 'J%'
AND LEFT(PHONE,1) = '1'
so it would show in the file as two conditions are met, but as i have over 80 rows and 40 conditions, its hard to look at each row and find out why its in their.
Is there a way i can add a column which will tell me which WHERE condition has been met?
As worded, no. You should reverse your logic. Add fields that show what's wrong, then use those fields in a WHERE clause.
SELECT
*,
CASE WHEN LEFT(phone, 1) = '1' THEN 1 ELSE 0 END AS phone_starts_with_1,
CASE WHEN LEFT(name, 1) = 'Z' THEN 1 ELSE 0 END AS name_starts_with_z
FROM
customers
WHERE
phone_starts_with_1 = 1
OR name_starts_with_z = 1
Depending on which dialect of SQL you use, you may need to nest this, such that the new fields are resolved before you can use them in the WHERE clause...
SELECT
*
FROM
(
SELECT
*,
CASE WHEN LEFT(phone, 1) = '1' THEN 1 ELSE 0 END AS phone_starts_with_1,
CASE WHEN LEFT(name, 1) = 'Z' THEN 1 ELSE 0 END AS name_starts_with_z
FROM
customers
)
checks
WHERE
phone_starts_with_1 = 1
OR name_starts_with_z = 1

SQL Query - combine 2 rows into 1 row

I have the following query below (view) in SQL Server. The query produces a result set that is needed to populate a grid. However, a new requirement has come up where the users would like to see data on one row in our app. The tblTasks table can produce 1 or 2 rows. The issue becomes when they're is two rows that have the same job_number but different fldProjectContextId (1 or 31). I need to get the MechApprovalOut and ElecApprovalOut columns on one row instead of two.
I've tried restructuring the query using CTE and over partition and haven't been able to get the necessary results I need.
SELECT TOP (100) PERCENT
CAST(dbo.Job_Control.job_number AS int) AS Job_Number,
dbo.tblTasks.fldSalesOrder, dbo.tblTaskCategories.fldTaskCategoryName,
dbo.Job_Control.Dwg_Sent, dbo.Job_Control.Approval_done,
dbo.Job_Control.fldElecDwgSent, dbo.Job_Control.fldElecApprovalDone,
CASE WHEN DATEDIFF(day, dbo.Job_Control.Dwg_Sent, GETDATE()) > 14
AND dbo.Job_Control.Approval_done IS NULL
AND dbo.tblProjectContext.fldProjectContextID = 1
THEN 1 ELSE 0
END AS MechApprovalOut,
CASE WHEN DATEDIFF(day, dbo.Job_Control.fldElecDwgSent, GETDATE()) > 14
AND dbo.Job_Control.fldElecApprovalDone IS NULL
AND dbo.tblProjectContext.fldProjectContextID = 31
THEN 1 ELSE 0
END AS ElecApprovalOut,
dbo.tblProjectContext.fldProjectContextName,
dbo.tblProjectContext.fldProjectContextId, dbo.Job_Control.Drawing_Info,
dbo.Job_Control.fldElectricalAppDwg
FROM dbo.tblTaskCategories
INNER JOIN dbo.tblTasks
ON dbo.tblTaskCategories.fldTaskCategoryId = dbo.tblTasks.fldTaskCategoryId
INNER JOIN dbo.Job_Control
ON dbo.tblTasks.fldSalesOrder = dbo.Job_Control.job_number
INNER JOIN dbo.tblProjectContext
ON dbo.tblTaskCategories.fldProjectContextId = dbo.tblProjectContext.fldProjectContextId
WHERE (dbo.tblTaskCategories.fldTaskCategoryName = N'Approval'
OR dbo.tblTaskCategories.fldTaskCategoryName = N'Re-Approval')
AND (CASE WHEN DATEDIFF(day, dbo.Job_Control.Dwg_Sent, GETDATE()) > 14
AND dbo.Job_Control.Approval_done IS NULL
AND dbo.tblProjectContext.fldProjectContextID = 1
THEN 1 ELSE 0
END = 1)
OR (dbo.tblTaskCategories.fldTaskCategoryName = N'Approval'
OR dbo.tblTaskCategories.fldTaskCategoryName = N'Re-Approval')
AND (CASE WHEN DATEDIFF(day, dbo.Job_Control.fldElecDwgSent, GETDATE()) > 14
AND dbo.Job_Control.fldElecApprovalDone IS NULL
AND dbo.tblProjectContext.fldProjectContextID = 31
THEN 1 ELSE 0
END = 1)
ORDER BY dbo.Job_Control.job_number, dbo.tblTaskCategories.fldProjectContextId
The above query gives me the following result set:
I've created a work around via code (which I don't like but it works for now) where i've used code to populate a "temp" table the way i need it to display the data, that is, one record if duplicate job numbers to get the MechApprovalOut and ElecApprovalOut columns on one row (see first record in following screen shot).
Example:
With the desired result set and one row per job_number, this is how the form looks with the data and how I am using the result set.
Any help restructuring my query to combine duplicate rows with the same job number where MechApprovalOut and ElecApproval out columns are on one row is greatly appreciated! I'd much prefer to use a view on SQL then code in the app to populate a temp table.
Thanks,
Jimmy
What I would do is LEFT JOIN the main table to itself at the beginning of the query, matching on Job Number and Sales Order, such that the left side of the join is only looking at Approval task categories and the right side of the join is only looking at Re-Approval task categories. Then I would make extensive use of the COALESCE() function to select data from the correct side of the join for use later on and in the select clause. This may also be the piece you were missing to make a CTE work.
There is probably also a solution that uses a ranking/windowing function (maybe not RANK itself, but something that category) along with the PARTITION BY clause. However, as those are fairly new to Sql Server I haven't used them enough personally to be comfortable writing an example solution for you without direct access to the data to play with, and it would still take me a little more time to get right than I can devote to this right now. Maybe this paragraph will motivate someone else to do that work.

SQL Server Update via Select Statement

I have the following sql statement and I want to update a field on the rows returned from the select statement. Is this possible with my select? The things I have tried are not giving me the desired results:
SELECT
Flows_Flows.FlowID,
Flows_Flows.Active,
Flows_Flows.BeatID,
Flows_Flows.FlowTitle,
Flows_Flows.FlowFileName,
Flows_Flows.FlowFilePath,
Flows_Users.UserName,
Flows_Users.DisplayName,
Flows_Users.ImageName,
Flows_Flows.Created,
SUM(CASE WHEN [Like] = 1 THEN 1 ELSE 0 END) AS Likes,
SUM(CASE WHEN [Dislike] = 1 THEN 1 ELSE 0 END) AS Dislikes
FROM Flows_Flows
INNER JOIN Flows_Users ON Flows_Users.UserID = Flows_Flows.UserID
LEFT JOIN Flows_Flows_Likes_Dislikes ON
Flows_Flows.FlowID=Flows_Flows_Likes_Dislikes.FlowID
WHERE Flows_Flows.Active = '1' AND Flows_Flows.Created < DATEADD(day, -60, GETDATE())
Group By Flows_Flows.FlowID, Flows_Flows.Active, Flows_Flows.BeatID,
Flows_Flows.FlowTitle, Flows_Flows.FlowFileName, Flows_Flows.FlowFilePath,
Flows_Users.UserName, Flows_Users.DisplayName, Flows_Users.ImageName,
Flows_Flows.Created
Having SUM(CASE WHEN [Like] = 1 THEN 1 ELSE 0 END) = '0' AND SUM(CASE WHEN [Dislike] = 1
THEN 1 ELSE 0 END) >= '0'
This select statement returns exactly what I need but I want to change the Active field from 1 to 0.
yes - the general structure might be like this: (note you don't declare your primary key)
UPDATE mytable
set myCol = 1
where myPrimaryKey in (
select myPrimaryKey from mytable where interesting bits happen here )
Because you haven't made your question more clear in what result you want to achieve, I'll provide an answer with my own assumptions.
Assumption
You have a select statement that gives you stuffs, and it works as desired. What you want it to do is to make it return results and update those selected rows on the fly - basically like saying "find X, tell me about X and make it Y".
Anwser
If my assumption is correct, unfortunately I don't think there is any way you can do that. A select does not alter the table, it can only fetch information. Similarly, an update does not provide more detail than the number of rows updated.
But don't give up yet, depending on the result you want to achieve, you have alternatives.
Alternatives
If you just want to update the rows that you have selected, you can
simply write an UPDATE statement to do that, and #Randy has provided
a good example of how it will be written.
If you want to reduce calls to server, meaning you want to make just
one call to the server and get result, as well as to update the
rows, you can write store procedures to do that.
Store procedures are like functions you wrote in programming languages. It essentially defines a set of sql operations and gives them a name. Each time you call that store procedure, the set of operations gets executed with supplied inputs, if any.
So if you want to learn more about store procedures you can take a look at:
http://www.mysqltutorial.org/introduction-to-sql-stored-procedures.aspx
If I understand correctly you are looking for a syntax to be able to select the value of Active to be 0 if it is 1. The syntax for something like that is
SELECT
Active= CASE WHEN Active=1 THEN 0 ELSE Active END
FROM
<Tables>
WHERE
<JOIN Conditions>