SQL History Query - sql

I need to select data from a inventory history table. The main part of my query will pull:
select *
from inv_history
where updated_date between '2-sep-14' and '8-sep-14'
and inv_STATUS = 'ON HAND'
Then I also need to include the record of this data before the status went to 'ON HAND'. Any tips would be appreciated.

Introduce a AFTER UPDATE trigger when the inv_status changes to ON HAND
This link could help you.

where updated_date between '2-sep-14' and '8-sep-14'
Your query predicate is incorrect. You must need to apply TO_DATE to the date literals.
To answer your question regarding including the records before the status went to "ON HAND", add the following query to your query using UNION ALL :
select *
from inv_history
where updated_date > ( select min(updated_date) from inv_history where between inv_STATUS = 'ON HAND')
I would rather use subquery factoring to have the rows from inv_history as:
with data as(
Select * from inv_history
where inv_status= 'ON_HAND'
Use the above just once rather then accessing the inv_history twice.

Related

Conversion failed when converting the varchar value 'Collect_Date' to data type int

I am struggling with trying to apply a date filter to my query. I keep getting this error message
Conversion failed when converting the varchar value 'Collect_Date' to
data type int
Here is my code:
SELECT
Location_ID,
CONVERT(Date,CONVERT(varchar(10),Collect_Month_Key,101)) as 'Collect_Date',
Calc_Gross_Totals, Loc_Country,
CONVERT(varchar(8),Collect_Month_Key)+'-'+Location_ID as 'Unique Key'
FROM
FT_GPM_NPM_CYCLES,
LU_Location,
LU_Loc_Country
WHERE
LU_Location.LU_Loc_Country_Key=LU_Loc_Country.LU_Loc_Country_Key
AND FT_GPM_NPM_CYCLES.Lu_Loc_Key= LU_Location.LU_Loc_Key
AND Collect_Month_Key<>-1
AND 'Collect_Date'>=2016-1-1
ORDER BY
Location_ID,
Collect_Date;
If someone could help that would be appreciated. I am also getting a different error when I try to do the Month(Collect_Date). So if anyone knows why on that I would appreciate it. I have attched a picture with the code nd results I am getting.
I see whats going on, you are trying to use the alias in the select statement. You can't do that, There are a few other issues that have been covered in the comments, but here is the immediate answer to the question:
Select Location_ID
, Convert(Date,CONVERT(varchar(10),Collect_Month_Key,101)) as Collect_Date
, Calc_Gross_Totals
, Loc_Country
, CONVERT(varchar(8),Collect_Month_Key)+'-'+Location_ID as [Unique Key]
From FT_GPM_NPM_CYCLES
, LU_Location
, LU_Loc_Country
Where LU_Location.LU_Loc_Country_Key=LU_Loc_Country.LU_Loc_Country_Key
and FT_GPM_NPM_CYCLES.Lu_Loc_Key= LU_Location.LU_Loc_Key
and Collect_Month_Key <> -1
and Convert(Date,CONVERT(varchar(10),Collect_Month_Key,101)) >= '2016-1-1'
Order By Location_ID, Collect_Date;
Here is an updated query that brings following modifications:
As commented by Robert Sheahan, you cannot use a resultset column alias in the WHERE clause
As commented by Larnu, since you are storing dates as strings, you could simply do string comparaison to filter records (and return string values). With this technique, you do not need additional condition Collect_Month_Key <> -1, since string '-1' is not greater than string '20160101'.
use explicit joins instead of implicit joins (comment by Gordon Linoff)
I added table aliases : they make the query easier to read (and make it possible to self-join a table...)
I would also recommend to to prefix all columns being used in the query with their table alias. This clearly indicates from which table each column comes from, and makes the query easier to understand and maintain. NB: if Collect_Month_Key belongs to a table other than FT_GPM_NPM_CYCLES, you want to move the condition from the WHERE clause to the ON clause of the relevant JOIN)
Query:
SELECT
Location_ID,
Collect_Month_Key AS Collect_Date,
Calc_Gross_Totals,
Loc_Country,
CONVERT(varchar(8),Collect_Month_Key) + '-' + Location_ID AS Unique_Key
FROM
FT_GPM_NPM_CYCLES AS cyc
INNER JOIN LU_Location AS loc
ON cyc.Lu_Loc_Key = loc.LU_Loc_Key
INNER JOIN LU_Loc_Country AS cty
ON loc.LU_Loc_Country_Key = cty.LU_Loc_Country_Key
WHERE
Collect_Month_Key > '20160101'
ORDER BY
Location_ID,
Collect_Month_Key
To answer your comment "So if I don't put the collect_Date in the WHERE, where should I put it for something like this in the future?", I suggest Common Table Expressions. Functionally they are equivalent to defining a derived table in the FROM clause, but they move it "above" so it feels more like "before" and I think they make it much easier to read. To convert GMB's excellent solution to using a CTE:
--Leading ; because CTEs require prvious command terminated explicitly
;WITH cteWithDates as ( --cteDates becomes a virtual temporary table
SELECT
cyc.* --Keep all the original columns of FT_GPM_NPM_CYCLES
, Collect_Month_Key AS Collect_Date --and add Collect_Date and Unique_Key
, CONVERT(varchar(8),Collect_Month_Key) + '-' + Location_ID AS Unique_Key
FROM FT_GPM_NPM_CYCLES AS cyc
) --you could add more CTEs with the following format,
--all become available at the end
--, cteMore as (SELECT ... FROM ...)
--the first line after the closing ) has access to all CTEs, but ONLY that line
SELECT Location_ID,
Collect_Date,
Calc_Gross_Totals,
Loc_Country,
Unique_Key
FROM
cteWithDates AS cyc --Use the CTE as you would your original table,
--but the added fields are now available EVERYWHERE in your query!
INNER JOIN LU_Location AS loc
ON cyc.Lu_Loc_Key = loc.LU_Loc_Key
INNER JOIN LU_Loc_Country AS cty
ON loc.LU_Loc_Country_Key = cty.LU_Loc_Country_Key
WHERE
Collect_Date > '20160101' --NOW you can use CollectDate!
ORDER BY
Location_ID,
Collect_Date --And here too
Note that this is much more efficient than defining an actual temporary table with #TableName, because the query optimizer can drop unused records from the CTE but it has to put them all into the #temporary table, a huge performance difference if your table is large and the matching subset small.

SQL Server : compare two tables with UNION and Select * plus additional label column

I've been playing around with the sample on Jeff' Server blog to compare two tables to find the differences.
In my case the tables are a backup and the current data. I can get what I want with this SQL statement (simplified by removing most of the columns). I can then see the rows from each table that don't have an exact match and I can see from which table they come.
SELECT
MIN(TableName) as TableName
,[strCustomer]
,[strAddress1]
,[strCity]
,[strPostalCode]
FROM
(SELECT
'Old' as TableName
,[JAS001].[dbo].[AR_CustomerAddresses].[strCustomer]
,[JAS001].[dbo].[AR_CustomerAddresses].[strAddress1]
,[JAS001].[dbo].[AR_CustomerAddresses].[strCity]
,[JAS001].[dbo].[AR_CustomerAddresses].[strPostalCode]
FROM
[JAS001].[dbo].[AR_CustomerAddresses]
UNION ALL
SELECT
'New' as TableName
,[JAS001new].[dbo].[AR_CustomerAddresses].[strCustomer]
,[JAS001new].[dbo].[AR_CustomerAddresses].[strAddress1]
,[JAS001new].[dbo].[AR_CustomerAddresses].[strCity]
,[JAS001new].[dbo].[AR_CustomerAddresses].[strPostalCode]
FROM
[JAS001new].[dbo].[AR_CustomerAddresses]) tmp
GROUP BY
[strCustomer]
,[strAddress1]
,[strCity]
,[strPostalCode]
HAVING
COUNT(*) = 1
This Stack Overflow Answer gives me a much cleaner SQL query but does not tell me from which table the rows come.
SELECT * FROM [JAS001new].[dbo].[AR_CustomerAddresses]
UNION
SELECT * FROM [JAS001].[dbo].[AR_CustomerAddresses]
EXCEPT
SELECT * FROM [JAS001new].[dbo].[AR_CustomerAddresses]
INTERSECT
SELECT * FROM [JAS001].[dbo].[AR_CustomerAddresses]
I could use the first version but I have many tables that I need to compare and I think that there has to be an easy way to add the source table column to the second query. I've tried several things and googled to no avail. I suspect that maybe I'm just not searching for the correct thing since I'm sure it's been answered before.
Maybe I'm going down the wrong trail and there is a better way to compare the databases?
Could you use the following setup to accomplish your goal?
SELECT 'New not in Old' Descriptor, *
FROM
(
SELECT * FROM [JAS001new].[dbo].[AR_CustomerAddresses]
EXCEPT
SELECT * FROM [JAS001].[dbo].[AR_CustomerAddresses]
) a
UNION
SELECT 'Old not in New' Descriptor, *
FROM
(
SELECT * FROM [JAS001].[dbo].[AR_CustomerAddresses]
EXCEPT
SELECT * FROM [JAS001new].[dbo].[AR_CustomerAddresses]
) b
You can't add the table name there because union, except, and intersection all compare all columns. This means you can't differentiate between them by adding the table name to the query. A group by gives you control over what columns are considered in finding duplicates so you can exclude the table name.
To help you with the large number of tables you need to compare you could write a sql query off the metadata tables that hold table names and columns and generate the sql commands dynamically off those values.
Derive one column using table names like below
SELECT MIN(TableName) as TableName
,[strCustomer]
,[strAddress1]
,[strCity]
,[strPostalCode]
,table_name_came
FROM
(SELECT 'Old' as TableName
,[JAS001].[dbo].[AR_CustomerAddresses].[strCustomer]
,[JAS001].[dbo].[AR_CustomerAddresses].[strAddress1]
,[JAS001].[dbo].[AR_CustomerAddresses].[strCity]
,[JAS001].[dbo].[AR_CustomerAddresses].[strPostalCode]
,'[JAS001].[dbo].[AR_CustomerAddresses]' as table_name_came
FROM [JAS001].[dbo].[AR_CustomerAddresses]
UNION ALL
SELECT 'New' as TableName
,[JAS001new].[dbo].[AR_CustomerAddresses].[strCustomer]
,[JAS001new].[dbo].[AR_CustomerAddresses].[strAddress1]
,[JAS001new].[dbo].[AR_CustomerAddresses].[strCity]
,[JAS001new].[dbo].[AR_CustomerAddresses].[strPostalCode]
,'[JAS001new].[dbo].[AR_CustomerAddresses]' as table_name_came
FROM [JAS001new].[dbo].[AR_CustomerAddresses]
) tmp
GROUP BY [strCustomer]
,[strAddress1]
,[strCity]
,[strPostalCode]
,table_name_came
HAVING COUNT(*) = 1

sql insert using select, case and subquery inside

select * into #transacTbl from tmpTrans
insert
select
(case when tmpT.TranStatus = 10
then(
select ID, 'Returned')
else(
select ID, 'GoodSale')
end)
from
(
select * from MainTransacSource
) as tmpT
I want to be able to insert the details of a transaction into a different table with a label if it is a returned or good sale/transaction. I did this to avoid the cursor so please avoid giving a solution using a cursor.
I know the code looks good but what I'm experiencing is that, the case statement only returns one value via subquery.
This is a simplified version of the code; I have at least 6 types of cases and should be able to insert by ROW. I hate to think that I have to repeat each case per column because the actual number of columns is about 38.
You may suggest another work-around if this doesn't fit the logic. Of course, without a cursor.
Without access to your tables and not knowing more about what precisely you want to acheive, try something like this:
select * into #transacTbl from tmpTrans
insert
select tmpT.ID,
(case when tmpT.TranStatus = 10
then 'Returned'
else 'GoodSale'
end)
from
(select * from MainTransacSource) as tmpT <OR simply MainTransacSource tmpT (maybe)>
Cheers.

Evaluate a varchar2 string into a condition for a SQL statement

I'm trying to find which rows are missing from 1 database to another, I already have link to the both DBs and I already found out that I can't just join separate tables so what I'm trying right now is select the ID's from one table and paste them into the select statement for the other DB however I don't know how to parse a clob into a condition.
let me explain further:
I got this collection of varchar2's with all the ID's i need to check on the other DB, and I can iterate through that collection so I get a clob with form: 'id1','id2','id3'
I want to run this query on the other DB
SELECT * FROM atable#db2
WHERE id NOT IN (clob_with_ids)
but I don't know how to tell PL/SQL to evaluate that clob as part of the statement.
id field on atable#db2 is an integer and the varchar2 id's I got are from runnning a regex on a clob
edit:
I've been ask to add the example I was trying to run:
SELECT *
FROM myTable#db1
WHERE ( (creation_date BETWEEN to_date('14-JUN-2011 00:00:00','DD-MON-YYYY HH24:MI:SS') AND to_date('14-JUN-2011 23:59:59','DD-MON-YYYY HH24:MI:SS')) )
AND acertain_id NOT IN ( SELECT to_number(REGEXP_REPLACE(REGEXP_REPLACE(REGEXP_SUBSTR(payload,'<xmlTag>([[:alnum:]]+)-'),'<xmlTag>',''),'-','')) as sameIDasOtherTable
FROM anotherTable#db2
WHERE condition1 ='bla'
AND condition2 ='blabla'
AND ( (creation_date BETWEEN to_date('14-JUN-2011 00:00:00','DD-MON-YYYY HH24:MI:SS') AND to_date('14-JUN-2011 23:59:59','DD-MON-YYYY HH24:MI:SS')) ) )
ORDER BY TO_CHAR(creation_date, 'MM/DD/YYYY') ASC;
I get error ORA-22992
Any suggestiongs?
It seems to me you have invested a lot of time in developing the wrong solution. A way simpler solution would be to use a SET operator. This query retrieves all the IDs in the local instance of ATABLE which are missing in the remote instance of the same table:
select id from atable
minus
select id from atable#db2
If your heart is set on retrieving the whole local row, you could try an anti-join:
select loc.*
from atable loc
left join atable#db2 rem
on (loc.id = rem.id )
where rem.id is null
/
I don't believe you can do that, but I've been proved wrong on many occasions... Even if you could find a way to get it to treat the contents of the CLOB as individual values for the IN you'd probably hit the 1000-item limit (ORA-01795) fairly quickly.
I'm not sure what you mean by 'I already found out that I can't just join separate tables'. Why can't you do something like:
SELECT * FROM atable#db2 WHERE id NOT IN (SELECT id FROM atable#db1)
Or:
SELECT * from atable#db2 WHERE id IN (
SELECT id FROM atable#db2 MINUS SELECT id FROM atable#db1)
(Or use #APC's anti-join, which is probably more performant!)
There may be performance issues with joining large tables on remote databases, but it looks like you have to do that at some point, and if it's a one-off task then it might be bearable.
Edited after question updated with join error
The ORA-22992 is because you're trying to pull a CLOB from the the remote database, which doesn't seem to work. From this I assume your reference to not being able to join is because you're joining two remote tables.
The simple option is not to pull all the columns - specify which you need rather than doing a select *. If you do need the CLOB value, the only thing I can suggest trying is using a CTE (WITH tmp_ids AS (SELECT <regex> FROM anotherTable#db2) ...), but I really have no idea if that avoids the two-link restriction. Or pull the IDs into a local temporary table; or run the query on one of the remote databases.

TRANSACT SQL - How to manually order/index a table based upon a select/where statement

I have sql puzzler today.
I have the following sql :
SELECT MemberId,
UnitId,
MaterialLevel,
MaterialText,
ProductPercentage,
ProductPriority
FROM tblWeights
ORDER BY MemberId, MaterialLevel, MaterialText, ProductPercentage DESC
Now, currently the ProductPriority is empty. What I would like to do is update this so that the first product, per level, per materialtext with the highest product percentage with "1", the second highest percentage with "2", etc, etc.
However, when the materialtext changes, this should reset itself and and start again at "1".
Can anyone think how I can do this?
Is there any reason you want productpriority explicitly stored in the database? Sorry if I've misunderstood your question but this sounds like it could be handled with a straight ROW_NUMBER in the output query.
You can use this for the initial update:
UPDATE tblWeights w1
SET ProductPriority = (
SELECT COUNT(*)
FROM tblWeights w2
WHERE w2.level = w1.level
AND w2.materialText = w1.materialText
AND w2.ProductPercentage >= w1.ProductPercentage
)
For the automatic reset, you should probably write a trigger that fires at the statement level after DELETE, UPDATE and INSERT. You can use a modified version of this statement, and only update the rows having the affected level,materialtext combination
CREATE TRIGGER aiud_tblWeights ON tblWeights
FOR INSERT, UPDATE, DELETE
AS
IF( UPDATE (Level) OR UPDATE (MaterialText) )
BEGIN
UPDATE tblWeights w1
SET ProductPriority = (
SELECT COUNT(*)
FROM tblWeights w2
WHERE w2.level = w1.level
AND w2.materialText = w1.materialText
AND w2.ProductPercentage >= w1.ProductPercentage
)
WHERE (w1.level, w1.materialText) IN (
SELECT level, materialText
FROM inserted
UNION ALL
SELECT level, materialText
FROM deleted
);
END;
I know its too late. but I found one answer when I was looking for similar questions for my help. see if helps someone else.
SQL query results to be displayed in the order of the manually provided values