I want to know how my sql like this my problem is every i remove my where clause in my code there have a error (Conversion failed when converting date and/or time from character string.) i remove may where clause because i want to see my all data, the figure below is example only i have so many data
This is the 1st table
| Entries | recordDate | Empid | Reference |
+-----------------------+-------------------------+--------+-----------+
| 0016930507201907:35I | 2019-05-07 00:00:00 000 | 001693 | 1693 |
| 0016930507201917:06O | 2019-05-07 00:00:00 000 | 001693 | 1693 |
| 0016930507201907:35I | 2019-05-08 00:00:00 000 | 001693 | 1693 |
| | 2019-05-08 00:00:00 000 | 001693 | 1693 |
2nd table
| LastName | FirstName | middleName | EmployeeNO |
+----------+-----------+------------+------------+
| Cruz | MA Kimberly | Castillo | 001693 |
this is i want to see
| Name | EmployeeNO | RecordDate | TimeIn | TimeOut |
+-------------------------+------------+-------------------------+--------+---------+
| CRUZ, MA KIMBERLY, CASTILLO | 001693 | 2019-05-07 00:00:00 000 | 07:35am | 05:06pm |
| CRUZ, MA KIMBERLY,CASTILLO | 001693 | 2019-05-08 00:00:00 000 | 07:35am |
this is my code please help me thank you advance for your helping
Select
B.LastName + ',' + B.FirstName + ',' + B.MiddleName[Name] ,
A.[RecordDate],
B.[EmployeeNO],
CONVERT(VARCHAR(08),MIN(IIF(ISNULL(CHARINDEX('I', A.[Entries], 0), 1) > 0, CAST( SUBSTRING(A.[Entries], LEN(A.[Entries]) - 5, 5) AS [TIME]), NULL)), 100) AS [TimeIn],
CONVERT(VARCHAR(08),MAX(IIF(ISNULL(CHARINDEX('O', A.[Entries], 0), 1) > 0,CAST(SUBSTRING(A.[Entries], LEN(A.[Entries]) - 5, 5) AS [TIME]), NULL)),100) AS [TimeOut]
FROM Employees [B]
INNER JOIN [DTR Upload] [A] ON B.EmployeeNo = A.EmpID
GROUP BY B.LastName, B.FirstName, B.MiddleName,B.[EmployeeNO], A.[recordDate]
ORDER BY A.[recordDate] asc, B.LastName +','+B.FirstName + ','+ B.MiddleName ASC
This works for the sample data you have provided. Note however, I assume that recordDate is a varchar, due to it not being a valid datetime value (if it were, 2019-05-07 00:00:00 000 would be 2019-05-07 00:00:00.000; note the . instead of the ). If recordDate isn't a varchar then you won't need need to include the STUFF and CONVERT expressions to "fix" the value in the VALUES operator. Really, however, you should not be storing date(time) data as a varchar; use the appropriate data type for your data (as these values have no time portion other than midnight, date would seem best).
I also return the TimeIn and TimeOut columns as the datatype time. Date and Time datatypes, in SQL Server, don't have a format they are binary values. If you want to display it in a 12 hour format then you need to configure that in your presentation layer, not your SQL:
--Table1 Sample Data
WITH Table1 AS(
SELECT V.Entries,
V.recordDate,
V.Empid,
V.Reference
FROM (VALUES('0016930507201907:35I','2019-05-07 00:00:00 000','001693',1693),
('0016930507201917:06O','2019-05-07 00:00:00 000','001693',1693),
('0016930507201907:35I','2019-05-08 00:00:00 000','001693',1693),
(NULL,'2019-05-08 00:00:00 000','001693',1693)) V(Entries,recordDate,Empid,Reference)),
--Table2 Sample Data
Table2 AS (
SELECT 'Cruz' AS LastName,
'MA Kimberly' AS FirstName,
'Castillo' AS middleName,
'001693' AS EmployeeNO)
--Solution
SELECT STUFF(CONCAT(', ' + T2.LastName, ', ' + T2.FirstName, ', ' + T2.middleName),1,2,'') AS [Name],
T2.EmployeeNO,
T1.recordDate,
MAX(CONVERT(time(0),CASE S.InOut WHEN 'I' THEN SUBSTRING(T1.Entries,15,5) END)) AS TimeIn,
MAX(CONVERT(time(0),CASE S.InOut WHEN 'O' THEN SUBSTRING(T1.Entries,15,5) END)) AS TimeOut
FROM Table1 T1
JOIN Table2 T2 ON T1.Empid = T2.EmployeeNO --These should really have the same name
CROSS APPLY(VALUES(CONVERT(datetime,STUFF(STUFF(T1.recordDate,11,1, 'T'),20,1,'.')),RIGHT(T1.Entries,1))) S(recordDate, InOut)
GROUP BY T2.EmployeeNO,
T1.recordDate,
T2.LastName,
T2.FirstName,
T2.middleName;
Is that what you are after?
;WITH CTE AS
(
SELECT EmployeeNO,
CONCAT(LastName, ',', FirstName, ',', MiddleName) Name,
RecordDate,
CASE WHEN RIGHT(Entries, 1) = 'I'
THEN CAST(REPLACE(RIGHT(Entries, 6), 'I', '') AS TIME)
END TimeIn,
CASE WHEN RIGHT(Entries, 1) = 'O'
THEN CAST(REPLACE(RIGHT(Entries, 6), 'O', '') AS TIME)
END TimeOut
FROM T1 INNER JOIN T2
ON T1.EmpId = T2.EmployeeNO
)
SELECT EmployeeNO,
Name,
RecordDate,
MIN(TimeIn) TimeIn,
MAX(TimeOut) TimeOut
FROM CTE
GROUP BY EmployeeNO,
Name,
RecordDate;
Returns:
+------------+------------------------+-------------------------+----------+----------+
| EmployeeNO | Name | RecordDate | TimeIn | TimeOut |
+------------+------------------------+-------------------------+----------+----------+
| 1693 | Cruz,Kimberly,Castillo | 2019-05-07 00:00:00 000 | 07:35:00 | 17:06:00 |
| 1693 | Cruz,Kimberly,Castillo | 2019-05-08 00:00:00 000 | 07:35:00 | |
+------------+------------------------+-------------------------+----------+----------+
Live Demo
Now, let's talk a bit about the real problems you have.
You are storing dates as string which is bad, always pick the right data type for your data, so you need to store dates as DATE. Also for the Entries has 3 info there, that means a lack of normalization, because it should be 3 column instead.
For example
+----------------+------+---------------------+
| Entries | Kind | EntriesDate |
+----------------+------+---------------------+
| 00169305072019 | 1 | 2019-05-07 07:35:00 |
| 00169305072019 | 0 | 2019-05-07 16:30:00 |
+----------------+------+---------------------+
This way, you won't fall in those issues and things becomes easy.
For the concatenation of the names, if you always needs to get a full name, I suggest that you use a computed column for that, then you don't need to concatenate the names every time
ALTER TABLE <Your Table Name Here>
ADD [FullName] AS CONCAT(LastName, ',', FirstName, ',', MiddleName);
Related
I have a hospital database which looks something like this:
id | patient_name | admitDate | DischargeDate
1 | john | 3/01/2011 08:50 | 5/01/2011 12:50
2 | lisa | 3/01/2011 09:50 | 4/01/2011 13:50
3 | ron | 5/01/2012 10:40 | 10/01/2012 03:50
4 | howard | 6/02/2013 08:05 | 10/02/2013 08:50
5 | john | 6/02/2013 12:04 | 7/02/2013 01:50
The admitDate is same for many entries (time may be different). I want to find out how many patients were admitted on any particular day so if I do this:
select distinct left(admitDate,10),
(select count(distinct left(admitDate,10) ) from hospital)
from hospital
I get output as all distinct admit dates in 1st column and same value 5 in all rows of second column. How do I make it so that only corresponding repetition count is found in 2nd column and not the count of entire admitDate set.
datatype of admitdate is varchar(50)
I am using left function because I only have to find out uniqueness in dates not in time.
Expected result:
admitDate | Count
3/01/2011 | 2
5/01/2012 | 1
6/02/2013 | 2
Current result:
admitDate | Count
3/01/2011 | 5
5/01/2012 | 5
6/02/2013 | 5
If your admitDate Column has Time too, you need use Convert() function to eliminate the time to group by your data per each day:
Select CONVERT(date, admitDate), count(*)
from hospital
group by CONVERT(date, admitDate);
If you use Varchar instead of Date data type for your admitDate column you can try this:
SELECT LEFT(admitDate, charindex(' ', admitDate) - 1) as ADMITDATE , count(*) as COUNTER
from hospital
group by LEFT(admitDate, charindex(' ', admitDate) - 1) ;
or:
SELECT convert(date, (convert(datetime2, admitDate,103)) ), count(*)
from hospital
group by convert(date, (convert(datetime2, admitDate,103)) )
I am trying to create a script whereby I am searching hundreds of Agent numbers for contacts and if no result returns I need a null in its place.
For example the below script will return
AgentNumber | Description | StartDate
------------------------------------------------
51702 | Terminal | 1900-01-01 00:00:00
10676 | RAMA | 1900-01-01 00:00:00
10585 | RAMA | 1900-01-01 00:00:00
What I need is for the results to show is where there is no data in the table:
AgentNumber | Description | StartDate
------------------------------------------------
51702 | Terminal | 1900-01-01 00:00:00
10676 | RAMA | 1900-01-01 00:00:00
10585 | RAMA | 1900-01-01 00:00:00
10001 | NULL | NULL
SET QUERY_GOVERNOR_COST_LIMIT 990
SELECT AgentNumber,description,startdate
FROM dbsSupport.dbo.ContractsIreland2
WHERE AgentNumber IN (51702,10676,10585,10001)
Presumably, you are using SQL Server based on the SET variable.
The solution to your problem is a LEFT JOIN. You can do it as:
SELECT v.AgentNumber, ci.description, ci.startdate
FROM (VALUES (51702), (10676), (10585), (10001)
) v(AgentNumber)
dbsSupport.dbo.ContractsIreland2 ci
ON ci.AgentNumber = v.AgentNumber;
You are looking for some kind of look-up table
select l.AgentNumber, c.description, c.startdate
from ( select 51702 as AgentNumber union
select 10676 as AgentNumber union
select 10585 as AgentNumber union
select 10001 as AgentNumber) l left join dbsSupport.dbo.ContractsIreland2 c
on c.AgentNumber = l.AgentNumber;
I am trying to track the usage of material with my SQL. There is no way in our database to link when a part is used to the order it originally came from. A part simply ends up in a bin after an order arrives, and then usage of parts basically just creates a record for the number of parts used at a time of transaction. I am attempting to, as best I can, link usage to an order number by summing over the data and sequentially assigning it to order numbers.
My sub queries have gotten me this far. Each order number is received on a date. I then join the usage table records based on the USEDATE needing to be equal to or greater than the RECEIVEDATE of the order. The data produced by this is as such:
| ORDERNUM | PARTNUM | RECEIVEDATE | ORDERQTY | USEQTY | USEDATE |
|----------|----------|-------------------------|-----------|---------|------------------------|
| 4412 | E1125 | 10/26/2016 1:32:25 PM | 1 | 1 | 11/18/2016 1:40:55 PM |
| 4412 | E1125 | 10/26/2016 1:32:25 PM | 1 | 3 | 12/26/2016 2:19:32 PM |
| 4412 | E1125 | 10/26/2016 1:32:25 PM | 1 | 1 | 1/3/2017 8:31:21 AM |
| 4111 | E1125 | 10/28/2016 2:54:13 PM | 1 | 1 | 11/18/2016 1:40:55 PM |
| 4111 | E1125 | 10/28/2016 2:54:13 PM | 1 | 3 | 12/26/2016 2:19:32 PM |
| 4111 | E1125 | 10/28/2016 2:54:13 PM | 1 | 1 | 1/3/2017 8:31:21 AM |
| 0393 | E1125 | 12/22/2016 11:52:04 AM | 3 | 3 | 12/26/2016 2:19:32 PM |
| 0393 | E1125 | 12/22/2016 11:52:04 AM | 3 | 1 | 1/3/2017 8:31:21 AM |
| 7812 | E1125 | 12/27/2016 10:56:01 AM | 1 | 1 | 1/3/2017 8:31:21 AM |
| 1191 | E1125 | 1/5/2017 1:12:01 PM | 2 | 0 | null |
The query for the above section looks as such:
SELECT
B.*,
NVL(B2.QTY, ‘0’) USEQTY
B2.USEDATE USEDATE
FROM <<Sub Query B>>
LEFT JOIN USETABLE B2 ON B.PARTNUM = B2.PARTNUM AND B2.USEDATE >= B.RECEIVEDATE
My ultimate goal here is to join USEQTY records sequentially until they have filled enough ORDERQTY’s. I also need to add an ORDERUSE column that represents what QTY from the USEQTY column was actually applied to that record. Not really sure how to word this any better so here is example of what I need to happen based on the table above:
| ORDERNUM | PARTNUM | RECEIVEDATE | ORDERQTY | USEQTY | USEDATE | ORDERUSE |
|----------|----------|-------------------------|-----------|---------|------------------------|-----------|
| 4412 | E1125 | 10/26/2016 1:32:25 PM | 1 | 1 | 11/18/2016 1:40:55 PM | 1 |
| 4111 | E1125 | 10/28/2016 2:54:13 PM | 1 | 3 | 12/26/2016 2:19:32 PM | 1 |
| 0393 | E1125 | 12/22/2016 11:52:04 AM | 3 | 2 | 12/26/2016 2:19:32 PM | 2 |
| 0393 | E1125 | 12/22/2016 11:52:04 AM | 3 | 1 | 1/3/2017 8:31:21 AM | 1 |
| 7812 | E1125 | 12/27/2016 10:56:01 AM | 1 | 0 | null | 0 |
| 1191 | E1125 | 1/5/2017 1:12:01 PM | 2 | 0 | null | 0 |
If I can get the query to pull the information like above, I will then be able to group the records together and sum the ORDERUSE column which would get me the information I need to know what orders have been used and which have not been fully used. So in the example above, if I were to sum the ORDERUSE column for each of the ORDERNUMs, orders 4412, 4111, 0393 would all show full usage. Orders 7812, 1191 would show not being fully used.
If i am reading this correctly you want to determine how many parts have been used. In your example it looks like you have 5 usages and with 5 orders coming to a total of 8 parts with the following orders having been used.
4412 - one part - one used
4111 - one part - one used
7812 - one part - one used
0393 - three
parts - two used
After a bit of hacking away I came up with the following SQL. Not sure if this works outside of your sample data since thats the only thing I used to test and I am no expert.
WITH data
AS (SELECT *
FROM (SELECT *
FROM sub_b1
join (SELECT ROWNUM rn
FROM dual
CONNECT BY LEVEL < 15) a
ON a.rn <= sub_b1.orderqty
ORDER BY receivedate)
WHERE ROWNUM <= (SELECT SUM(useqty)
FROM sub_b2))
SELECT sub_b1.ordernum,
partnum,
receivedate,
orderqty,
usage
FROM sub_b1
join (SELECT ordernum,
Max(rn) AS usage
FROM data
GROUP BY ordernum) b
ON sub_b1.ordernum = b.ordernum
You are looking for "FIFO" inventory accounting.
The proper data model should have two tables, one for "received" parts and the other for "delivered" or "used". Each table should show an order number, a part number and quantity (received or used) for that order, and a timestamp or date-time. I model both in CTE's in my query below, but in your business they should be two separate table. Also, a trigger or similar should enforce the constraint that a part cannot be used until it is available in stock (that is: for each part id, the total quantity used since inception, at any point in time, should not exceed the total quantity received since inception, also at the same point in time). I assume that the two input tables do, in fact, satisfy this condition, and I don't check it in the solution.
The output shows a timeline of quantity used, by timestamp, matching "received" and "delivered" (used) quantities for each part_id. In the sample data I illustrate a single part_id, but the query will work with multiple part_id's, and orders (both for received and for delivered or used) that include multiple parts (part id's) with different quantities.
with
received ( order_id, part_id, ts, qty ) as (
select '0030', '11A4', timestamp '2015-03-18 15:00:33', 20 from dual union all
select '0032', '11A4', timestamp '2015-03-22 15:00:33', 13 from dual union all
select '0034', '11A4', timestamp '2015-03-24 10:00:33', 18 from dual union all
select '0036', '11A4', timestamp '2015-04-01 15:00:33', 25 from dual
),
delivered ( order_id, part_id, ts, qty ) as (
select '1200', '11A4', timestamp '2015-03-18 16:30:00', 14 from dual union all
select '1210', '11A4', timestamp '2015-03-23 10:30:00', 8 from dual union all
select '1220', '11A4', timestamp '2015-03-23 11:30:00', 7 from dual union all
select '1230', '11A4', timestamp '2015-03-23 11:30:00', 4 from dual union all
select '1240', '11A4', timestamp '2015-03-26 15:00:33', 1 from dual union all
select '1250', '11A4', timestamp '2015-03-26 16:45:11', 3 from dual union all
select '1260', '11A4', timestamp '2015-03-27 10:00:33', 2 from dual union all
select '1270', '11A4', timestamp '2015-04-03 15:00:33', 16 from dual
),
(end of test data; the SQL query begins below - just add the word WITH at the top)
-- with
combined ( part_id, rec_ord, rec_ts, rec_sum, del_ord, del_ts, del_sum) as (
select part_id, order_id, ts,
sum(qty) over (partition by part_id order by ts, order_id),
null, cast(null as date), cast(null as number)
from received
union all
select part_id, null, cast(null as date), cast(null as number),
order_id, ts,
sum(qty) over (partition by part_id order by ts, order_id)
from delivered
),
prep ( part_id, rec_ord, del_ord, del_ts, qty_sum ) as (
select part_id, rec_ord, del_ord, del_ts, coalesce(rec_sum, del_sum)
from combined
)
select part_id,
last_value(rec_ord ignore nulls) over (partition by part_id
order by qty_sum desc) as rec_ord,
last_value(del_ord ignore nulls) over (partition by part_id
order by qty_sum desc) as del_ord,
last_value(del_ts ignore nulls) over (partition by part_id
order by qty_sum desc) as used_date,
qty_sum - lag(qty_sum, 1, 0) over (partition by part_id
order by qty_sum, del_ts) as used_qty
from prep
order by qty_sum
;
Output:
PART_ID REC_ORD DEL_ORD USED_DATE USED_QTY
------- ------- ------- ----------------------------------- ----------
11A4 0030 1200 18-MAR-15 04.30.00.000000000 PM 14
11A4 0030 1210 23-MAR-15 10.30.00.000000000 AM 6
11A4 0032 1210 23-MAR-15 10.30.00.000000000 AM 2
11A4 0032 1220 23-MAR-15 11.30.00.000000000 AM 7
11A4 0032 1230 23-MAR-15 11.30.00.000000000 AM 4
11A4 0032 1230 23-MAR-15 11.30.00.000000000 AM 0
11A4 0034 1240 26-MAR-15 03.00.33.000000000 PM 1
11A4 0034 1250 26-MAR-15 04.45.11.000000000 PM 3
11A4 0034 1260 27-MAR-15 10.00.33.000000000 AM 2
11A4 0034 1270 03-APR-15 03.00.33.000000000 PM 12
11A4 0036 1270 03-APR-15 03.00.33.000000000 PM 4
11A4 0036 21
12 rows selected.
Notes: (1) One needs to be careful if at one moment the cumulative used quantity exactly matches cumulative received quantity. All rows must be include in all the intermediate results, otherwise there will be bad data in the output; but this may result (as you can see in the output above) in a few rows with a "used quantity" of 0. Depending on how this output is consumed (for further processing, for reporting, etc.) these rows may be left as they are, or they may be discarded in a further outer-query with the condition where used_qty > 0.
(2) The last row shows a quantity of 21 with no used_date and no del_ord. This is, in fact, the "current" quantity in stock for that part_id as of the last date in both tables - available for future use. Again, if this is not needed, it can be removed in an outer query. There may be one or more rows like this at the end of the table.
I have an app that has the built in initial Select option and only allows me to enter from the Where section. I have rows with duplicate values. I'm trying to get the list of just one record for each distinct value but am unsure how to get the statement to work. I've found one that almost does the trick but it doesn't give me any rows that had a dup. I assume due to the = so just need a way to get one for each that matches my where criteria. Examples below.
Initial Data Set
Date | Name | ANI | CallIndex | Duration
---------------------------------------------------------
2/2/2015 | John | 5555051000 | 00000.0001 | 60
2/2/2015 | John | | 00000.0001 | 70
3/1/2015 | Jim | 5555051001 | 00000.0012 | 80
3/4/2015 | Susan | | 00000.0022 | 90
3/4/2015 | Susan | 5555051002 | 00000.0022 | 30
4/10/2015 | April | 5555051003 | 00000.0030 | 35
4/11/2015 | Leon | 5555051004 | 00000.0035 | 10
4/15/2015 | Jane | 5555051005 | 00000.0050 | 20
4/15/2015 | Jane | 5555051005 | 00000.0050 | 60
4/15/2015 | Kevin | 5555051006 | 00000.0061 | 35
What I Want the Query to Return
Date | Name | ANI | CallIndex | Duration
---------------------------------------------------------
2/2/2015 | John | 5555051000 | 00000.0001 | 60
3/1/2015 | Jim | 5555051001 | 00000.0012 | 80
3/4/2015 | Susan | 5555051002 | 00000.0022 | 30
4/10/2015 | April | 5555051003 | 00000.0030 | 35
4/11/2015 | Leon | 5555051004 | 00000.0035 | 10
4/15/2015 | Jane | 5555051005 | 00000.0050 | 20
4/15/2015 | Kevin | 5555051006 | 00000.0061 | 35
Here is what I was able to get but when i run it I don't get the rows that did have dups callindex values. duration doesn't mattern and they never match up so if it helps to query using that as a filter that would be fine. I've added mock data to assist.
use Database
SELECT * FROM table
WHERE Date between '4/15/15 00:00' and '4/15/15 23:59'
and callindex in
(SELECT callindex
FROM table
GROUP BY callinex
HAVING COUNT(callindex) = 1)
Any help would be greatly appreciated.
Ok with the assistance of everyone here i was able to get the query to work perfectly within SQL. That said apparently the app I'm trying this on has a built in character limit and the below query is too long. This is the query i have to use as far as the restrictions and i have to be able to search both ID's at the same time because some get stamped with one or the other rarely both. I'm hoping someone might be able to help me shorten it?
use Database
select * from tblCall
WHERE
flddate between '4/15/15 00:00' and '4/15/15 23:59'
and fldAgentLoginID='1234'
and fldcalldir='incoming'
and fldcalltype='external'
and EXISTS (SELECT * FROM (SELECT MAX(fldCallName) AS fldCallName, fldCallID FROM tblCall GROUP BY fldCallID) derv WHERE tblCall.fldCallName = derv.fldCallName AND tblCall.fldCallID = derv.fldCallID)
or
flddate between '4/15/15 00:00' and '4/15/15 23:59'
and '4/15/15 23:59'
and fldPhoneLoginID='56789'
and fldcalldir='incoming'
and fldcalltype='external'
and EXISTS (SELECT * FROM (SELECT MAX(fldCallName) AS fldCallName, fldCallID FROM tblCall GROUP BY fldCallID) derv WHERE tblCall.fldCallName = derv.fldCallName AND tblCall.fldCallID = derv.fldCallID)
If the constraint is that we can only add to the WHERE clause, I don't think it's possible, due to there being 2 absolutely identical rows:
4/15/2015 | Jane | 5555051005 | 00000.0050
4/15/2015 | Jane | 5555051005 | 00000.0050
Is it possible that you can add HAVING or GROUP BY to the WHERE? or possibly UNION the SELECT to another SELECT statement? That may open up some additional possibilities.
Maybe with an union:
SELECT *
FROM table
GROUP BY Date, Name, ANI, CallIndex
HAVING ( COUNT(*) > 1 )
UNION
SELECT *
FROM table
WHERE Name not in (SELECT name from table
GROUP BY Date, Name, ANI, CallIndex
HAVING ( COUNT(*) > 1 ))
From your sample, it seems like you could just exclude rows in which there was no value in the ANI column. If that is the case you could simply do:
use Database
SELECT * FROM table
WHERE Date between '4/15/15 00:00' and '4/15/15 23:59'
and ANI is not null
If this doesn't work for you, let me know and I can see what else I can do.
Edit:
You've made it sound like the CallIndex combined with the Duration is a unique value. That seems somewhat doubtful to me, but if that is the case you could do something like this:
use Database
SELECT * FROM table
WHERE Date between '4/15/15 00:00' and '4/15/15 23:59'
and cast(callindex as varchar(80))+'-'+cast(min(duration) as varchar(80)) in
(SELECT cast(callindex as varchar(80))+'-'+cast(min(duration) as varchar(80))
FROM table
GROUP BY callindex)
There are two keywords you can use to get non-duplicated data, either DISTINCT or GROUP BY. In this case, I would use a GROUP BY, but you should read up on both.
This query groups all of the records by CallIndex and takes the MAX value for each of the other columns and should give you the results you want:
SELECT MAX(Date) AS Date, MAX(Name) AS Name, MAX(ANI) AS ANI, CallIndex
FROM table
GROUP BY CallIndex
EDIT
Since you can't use GROUP BY directly but you can have any SQL in the WHERE clause you can do:
SELECT *
FROM table
WHERE EXISTS
(
SELECT *
FROM
(
SELECT MAX(Date) AS Date, MAX(Name) AS Name, MAX(ANI) AS ANI, CallIndex
FROM table
GROUP BY CallIndex
) derv
WHERE table.Date = derv.Date
AND table.Name = derv.Name
AND table.ANI = derv.ANI
AND table.CallIndex = derv.CallIndex
)
This selects all rows from the table where there exists a matching row from the GROUP BY.
It won't be perfect, if any two rows match exactly, you'll still have duplicates, but that's the best you'll get with your restriction.
In your data, why not just do this?
SELECT *
FROM table
WHERE Date >= '2015-04-15' and Date < '2015-04-16'
ani is not null;
If the blank values are only a coincidence, then you have a problem just using a where clause. If the results are full duplicates (no column has a different value), then you probably cannot do what you want with just a where clause -- unless you are using SQLite, Oracle, or Postgres.
I have a table with some columns:
WON param | machine | inputdate | val
---|-------------|------------|------------------|--------|
18 | PAR.SPTDM.X1| MM01 | 20/01/2013 12:43 | 2.5 |
18 | PAR.SPTDM.Y1| MM01 | 20/01/2013 12:43 | 3,4 |
22 | PAR.SPTDM.X1| MM01 | 22/01/2013 16:10 | 1.2 |
22 | PAR.SPTDM.Y1| MM01 | 22/01/2013 16:10 | 1.7 |
33 | PAR.SPTDM.X1| MM03 | 22/01/2013 16:13 | 2.34 |
33 | PAR.SPTDM.Y1| MM03 | 22/01/2013 16:13 | 2,21 |
27 | PAR.LAS.PWR | MM10 | 25/01/2013 08:14 | 100.5 |
14 | PAR.LAS.UV | MM10 | 18/01/2013 17:27 | 134.8 |
41 | PAR.LAS.UV | SLA4 | 27/01/2013 09:14 | 2,1 |
62 | PAR.LAS.UV | SLA5 | 27/01/2013 11:15 | 14.6 |
Some of these rows get duplicated (for reasons unknown to me, it's the backend for a management system). Also the value column is a string, it needs conversion to numbers.
The database is readonly, and I want to pull in data into an Excel sheet based on a few conditions:
group by machine and param
filter on param: only 'PAR.SPTDM.%'
filter on machine: only 'MM%'
ignore val's with a comma, convert the rest to numbers
This works without any problems using the following query:
SELECT DISTINCT t1.param, t1.machine, cast(t1.val as float), t1.inputdate
FROM dbbackend t1
WHERE (t1.machine Like 'MM%')
AND (t1.param Like 'PAR.SPTDM.%')
AND (t1.val<>'') And (t1.val not Like '%,%')
Now I want to only retrieve the records for each machine and each parameter (of interest) with the latest inputdate. First I tried
SELECT DISTINCT t1.param, t1.machine, max(cast(t1.val as float)), max(t1.inputdate)
FROM dbbackend t1
WHERE (t1.machine Like 'MM%')
AND (t1.param Like 'PAR.SPTDM.%')
AND (t1.val<>'') And (t1.val not Like '%,%')
GROUP BY machine, param
But this gave me val's which weren't in the dataset, correct machine/param/inputdate, but wrong val.
Next try was
SELECT DISTINCT t1.param, t1.machine, cast(t1.val as float), t1.inputdate
FROM dbbackend t1
WHERE t1.WON IN
(
SELECT latestrec.WON FROM (
SELECT DISTINCT max(t2.WON), t2.param, t2.machine, max(t2.inputdate)
FROM dbbackend t2
WHERE (t2.machine Like 'MM%')
AND (t2.param Like 'PAR.SPTDM.%')
AND (t2.val<>'') And (t2.val not Like '%,%')
GROUP BY machine, param
) as latestrec
)
But this wouldn't work, MS Query told me
Could not add the table '('.
So can someone tell me why I get wrong values with the first call, and why the second isn't working, or what is the correct method? I also suspect MS query to trip over that nested subquery :/
You could try this CTE with the ROW_NUMBER function:
WITH x AS (SELECT t1.param,
t1.machine,
Cast(t1.val AS FLOAT) AS val,
t1.inputdate,
RN=Row_number()
OVER(
partition BY t1.machine, t1.param
ORDER BY t1.inputdate DESC)
FROM dbbackend t1
WHERE ( t1.machine LIKE 'MM%' )
AND ( t1.param LIKE 'PAR.SPTDM.%' )
AND ( t1.val <> '' )
AND ( t1.val NOT LIKE '%,%' ))
SELECT param,
machine,
val,
inputdate
FROM x
WHERE rn = 1