So this is most likely a long shot.
I have a table named 'Case' that has primary key 'Case_ID'. In another table named 'CaseStatus' there is a column named 'value' which just has items like pending, researching,... etc.
My issue is everytime the status is updated, I am getting duplicate 'Case_ID's
How can I select the latest entry (essentially showing the current 'status')?
There is no date, however both tables share a column named 'Last_Mod_Date'. I am not sure if that helps. I have done tons of searching on here and most people are looking for something like a MAX DATE but my brain doesn't want to work for some reason and I cannot connect the dots.
I appreciate everyone's help. I have fixed it. I'd post it but probably won't make sense without seeing the whole picture... here is the relevant part I think:
where
B.[CASE_ID] = A.CASE_ID
and B.LAST_ONE = 'Y'
and C.[TYPE] = 'STATUS'
and [DIS].[TYPE] = 'DISPOSITION'
In the CaseStatus table you need to add a status change date. Without that you have no reliable way of getting the latest status.
Another option is to use an UPDATE instead of an INSERT when changing status. That way you will always have one row per case ID.
This will give you one row for the case and one for the case status.
select *
from [CASE] C
inner join
(select cs.CASE_ID, cs.Status
from CaseStatus cs
where C.[TYPE] = 'STATUS'
and cs.CaseStatus_ID in
(select max(s.CaseStatus_ID) maxID
from CaseStatus s
where s.[TYPE] = 'STATUS'
group by s.CASE_ID)) as cs
on c.Case_ID = cs.Case_ID
Normally you would just have a CASE.CaseStatusID column that would hold the latest status and then you would use triggers to capture the history if you ever needed it. Also, I would stay away from using reserved words like CASE for my object names.
Related
I am trying to build a table of Contact IDs (Primary Keys) of the most recently created records assigned to each Account of a certain type in our Salesforce org.
Working in Salesforce Marketing Cloud, I'm trying to build a sample list that I can setup to update automatically so the records I'm testing against are never stale. I only need one example from each account to do my testing. Since I want to make sure the record isn't stale, I want to select the most recent record assigned to each Account.
Every Contact is assigned to one and only one Account. The Account ID lives as a foreign key on the Contact Record. The created date of the Contact is also a field on the Contact record.
The Sample list needs to contain the email address, ContactID, and the name of the Management Company, which lives on the Account record.
I figured doing a directional JOIN toward the Account table would do the trick, but that didn't work. I figure that's because there's nothing distinguishing which record to pick.
This is what I've got for code, which is pretty useless...
SELECT
C.Email AS Email,
C.Id AS Id18,
C.AccountID AS AccountID,
A.Management_Company AS ManagementCompany
FROM
ENT.Contact_Salesforce_DE AS C
RIGHT JOIN ENT.Account_Salesforce_DE AS A ON C.AccountID = A.Id
WHERE
A.RecordTypeId = '1234567890ABCDEFGH' AND
A.Management_Company IS NOT NULL AND
C.Email IS NOT NULL
The syntax checks out, but I get a system error every time I run it.
Marketing Cloud runs on an older version of SQL Server, so some more recent query functions won't always work.
And yes, I'm a relative noob to SQL. Won't surprise me if this has a really simple solution, but I couldn't find another entry describing the solution, so...
If I followed you correctly, you want to pull out the latest contact associated with each account.
On database servers that do not support window function (which seems to be the case of your RDBMS), one typical solution is to add a special condition to the JOIN. This NOT EXISTS condition uses a subquery to ensure that the record being picked in the child table is the most recent one (in other words : there is no child record with a highest creation date than the one being joined) :
SELECT
c.Email AS Email,
c.Id AS Id18,
c.AccountID AS AccountID
FROM
ENT.Account_Salesforce_DE AS a
INNER JOIN ENT.Contact_Salesforce_DE AS c
ON c.AccountID = a.Id
AND c.email IS NOT NULL
AND NOT EXISTS (
SELECT 1
FROM ENT.Contact_Salesforce_DE AS c1
WHERE
c1.email IS NOT NULL
AND c1.AccountID = a.Id
AND c1.CreatedDate > c.CreatedDate
)
WHERE
A.RecordTypeId = '1234567890ABCDEFGH'
AND A.Management_Company IS NOT NULL
The requirement is to display activity records (S_EVT_ACT table) along with a new column in it to display whether the activity record contains any attachments or not.
Activity attachments belongs to S_ACTIVTY_ATT table and has relationship with parent activity as attachment's PAR_ROW_ID = activity's ROW_ID.
The new column can either display output as Y or N for each activity record. Also, the new column can either display the count of attachments for an activity.
what should be the SQL query in this case.
Use exists:
select a.*,
(case when exists (select 1
from S_ACTIVTY_ATT att
where att.PAR_ROW_ID = a.ROW_ID
)
then 'Y' else 'N'
end) as has_attachment
from S_EVT_ACT a;
In general, exists performs better than any solution with aggregation. In particular, with an index on att(PAR_ROW_ID) this should be quite fast.
if you really want to have a column, you have to populate (increase) the value each time you insert an attachment. If you only want to see it in an SELECT-Query, you could do something like this:
SELECT act.*, att.ATT_COUNT
FROM S_EVT_ACT act
LEFT OUTER JOIN (SELECT PAR_ROW_ID, COUNT(*) AS ATT_COUNT
FROM S_ACTIVTY_ATT
GROUP BY PAR_ROW_ID ) AS att ON (act.ROW_ID = att.PAR_ROW_ID)
Notice: it should work, but depending on your number of rows and other things i don't know there could be better solutions.
Hello I have a question regarding a query I am trying to create. I want to create a query that will List members'name for who ever checked out one oe more books and have returned ALL of them. I have a query (shown below that finds the entries if there Return Date is no NULL but I can't figure out how to now show the Names if they have a returned book but still have another book they have no returned (Return Date = NULL). Below is my script if anybody can give me some advice. Thank you.
SELECT MemName
FROM MEMBER, CHECK_OUT
WHERE MEMBER.ID = CHECK_OUT.MemID
AND CHECK_OUT.DateRet IS NOT NULL
If I understand what you are asking, you want a query that will return all members who currently have a book checked out, correct?
Something like this might be what you want:
SELECT
M.MemName
FROM
MEMBER AS M
INNER JOIN CHECK_OUT AS C ON (C.MemID = M.ID)
WHERE
C.DateRet IS NULL
This will list all member names that have something checked out, but will not remove duplicates. To list each name only one, use SELECT DISTINT. To get the names who do NOT have anything checked out anymore (but did at one point) use either your query or modify mine to say C.DateRet IS NOT NULL. I personally just like using INNER JOINS in this situation.
I want to create a query that will List members' names for who ever checked out one or more books and have returned ALL of them.
SELECT MEMBER.MemName
FROM MEMBER, CHECK_OUT
WHERE MEMBER.ID = CHECK_OUT.MemID
group by MEMBER.ID, MEMBER.MemName
having max(nvl2(CHECK_OUT.DateRet, 0, 1)) = 0
Downloads table:
id (primary key)
user_id
item_id
created_at
updated_at
The user_id and item_id in this case are both incorrect, however, they're properly stored in the users and items table, respectively (import_id for in each table). Here's what I'm trying to script:
downloads.each do |download|
user = User.find_by_import_id(download.user_id)
item = item.find_by_import_id(download.item_id)
if user && item
download.update_attributes(:user_id => user.id, :item.id => item.id)
end
end
So,
look up the user and item based on
their respective "import_id"'s. Then
update those values in the download record
This takes forever with a ton of rows. Anyway to do this in SQL?
If I understand you correctly, you simply need to add two sub-querys in your SELECT statement to lookup the correct IDs. For example:
SELECT id,
(SELECT correct_id FROM User WHERE import_id=user_id) AS UserID,
(SELECT correct_id FROM Item WHERE import_id=item_id) AS ItemID,
created_at,
updated_at
FROM Downloads
This will translate your incorrect user_ids to whatever ID you want to come from the User table and it will do the same for your item_ids. The information coming from SQL will now be correct.
If, however, you want to update the tables with the correct information, you could write this like so:
UPDATE Downloads
SET user_id = User.user_id,
item_id = Item.item_id
FROM Downloads
INNER JOIN User ON Downloads.user_id = User.import_id
INNER JOIN Item ON Downloads.item_id = Item.import_id
WHERE ...
Make sure to put something in the WHERE clause so you don't update every record in the Downloads table (unless that is the plan). I rewrote the above statement to be a bit more optimized since the original version had two SELECT statements per row, which is a bit intense.
Edit:
Since this is PostgreSQL, you can't have the table name in both the UPDATE and the FROM section. Instead, the tables in the FROM section are joined to the table being updated. Here is a quote about this from the PostgreSQL website:
When a FROM clause is present, what essentially happens is that the target table is joined to the tables mentioned in the fromlist, and each output row of the join represents an update operation for the target table. When using FROM you should ensure that the join produces at most one output row for each row to be modified. In other words, a target row shouldn't join to more than one row from the other table(s). If it does, then only one of the join rows will be used to update the target row, but which one will be used is not readily predictable.
http://www.postgresql.org/docs/8.1/static/sql-update.html
With this in mind, here is an example that I think should work (can't test it, sorry):
UPDATE Downloads
SET user_id = User.user_id,
item_id = Item.item_id
FROM User, Item
WHERE Downloads.user_id = User.import_id AND
Downloads.item_id = Item.import_id
That is the basic idea. Don't forget you will still need to add extra criteria to the WHERE section to limit the rows that are updated.
i'm totally guessing from your question, but you have some kind of lookup table that will match an import user_id with the real user_id, and similarly from items. i.e. the assumption is your line of code:
User.find_by_import_id(download.user_id)
hits the database to do the lookup. the import_users / import_items tables are just the names i've given to the lookup tables to do this.
UPDATE downloads
SET downloads.user_id = users.user_id
, downloads.item_id = items.items_id
FROM downloads
INNER JOIN import_users ON downloads.user_id = import_users.import_user_id
INNER JOIN import_items ON downloads.item_id = import_items.import_item_id
Either way (lookup is in DB, or it's derived from code), would it not just be easier to insert the information correctly in the first place? this would mean you can't have any FK's on your table since sometimes they point to one table, and others they point to another. seems a bit odd.
I'm implementing an audit log on a database, so everything has a CreatedAt and a RemovedAt column. Now I want to be able to list all revisions of an object graph but the best way I can think of for this is to use unions. I need to get every unique CreatedAt and RemovedAt id.
If I'm getting a list of countries with provinces the union looks like this:
SELECT c.CreatedAt AS RevisionId from Countries as c where localId=#Country
UNION
SELECT p.CreatedAt AS RevisionId from Provinces as p
INNER JOIN Countries as c ON p.CountryId=c.LocalId AND c.LocalId = #Country
UNION
SELECT c.RemovedAt AS RevisionId from Countries as c where localId=#Country
UNION
SELECT p.RemovedAt AS RevisionId from Provinces as p
INNER JOIN Countries as c ON p.CountryId=c.LocalId AND c.LocalId = #Country
For more complicated queries this could get quite complicated and possibly perform very poorly so I wanted to see if anyone could think of a better approach. This is in MSSQL Server.
I need them all in a single list because this is being used in a from clause and the real data comes from joining on this.
You have most likely already implemented your solution, but to address a few issues; I would suggest considering Aleris's solution, or some derivative thereof.
In your tables, you have a "removed at" field -- well, if that field were active (populated), technically the data shouldn't be there -- or perhaps your implementation has it flagged for deletion, which will break the logging once it is removed.
What happens when you have multiple updates during a reporting period -- the previous log entries would be overwritten.
Having a separate log allows for archival of the log information and allows you to set a different log analysis cycle from your update/edit cycles.
Add whatever "linking" fields required to enable you to get back to your original source data OR make the descriptions sufficiently verbose.
The fields contained in your log are up to you but Aleris's solution is direct. I may create an action table and change the field type from varchar to int, as a link into the action table -- forcing the developers to some standardized actions.
Hope it helps.
An alternative would be to create an audit log that might look like this:
AuditLog table
EntityName varchar(2000),
Action varchar(255),
EntityId int,
OccuranceDate datetime
where EntityName is the name of the table (eg: Contries, Provinces), the Action is the audit action (eg: Created, Removed etc) and the EntityId is the primary key of the modified row in the original table.
The table would need to be kept synchronized on each action performed to the tables. There are a couple of ways to do this:
1) Make triggers on each table that will add rows to AuditTable
2) From your application add rows in AuditTable each time a change is made to the repectivetables
Using this solution is very simple to get a list of logs in audit.
If you need to get columns from original table is also possible using joins like this:
select *
from
Contries C
join AuditLog L on C.Id = L.EntityId and EntityName = 'Contries'
You could probably do it with a cross join and coalesce, but the union is probably still better from a performance standpoint. You can try testing each though.
SELECT
COALESCE(C.CreatedAt, P.CreatedAt)
FROM
dbo.Countries C
FULL OUTER JOIN dbo.Provinces P ON
1 = 0
WHERE
C.LocalID = #Country OR
P.LocalID = #Country