I was stuck figuring out why there's error when I execute the mysql query on mssql query. I was using sql server 2000. My goal is to achieve the result with the same way that I use on mysql.
A little explanation about the database: The database is about a gps tracker with 3 main table: incoming, md_login, and master_device.
Here is the table and the structure that I will give:
Structure of table incoming:
This table mainly used for the incoming data of the gps tracker for each vehicle, so every interval there'll be incoming data into this tables. Regarding about some of the table structure, you can say 'tanggal' is the meaning of 'date' in English
Text1 varchar
...
Text18 varchar <used as imei>
...
Text31 varchar
Distance varchar
Tanggal datetime
TanggalIncoming datetime
StartDate datetime
EndDate datetime
EngineStatus varchar
AccStatus varchar
Moving varchar
Address varchar
Structure of table md_login:
This table used to store the vehicle with the imei data, so 1 Log_ID can have many Log_DeviceID.
Log_ID char <used as username>
Log_DeviceID varchar <used as vehicle number>
Log_DeviceIMEI varchar <used as imei>
Log_Date datetime
Sample data of table md_login:
Log_ID - Alex
Log_DeviceID - B 7777 GHI
Log_DeviceImei - 012896001194123
Log_Date - 2017-05-30 13:46:57
Structure of table master_device:
Device_Imei varchar
Device_PoliceNumber char
Device_MobileNumber char
Device_MobileNumber2 char
Model varchar
Port char
PortDevice char
ActiveDate datetime
LastUpdate datetime
IdxConn varchar
CommandOperate char
Picture varchar
Sample data of table master_device:
Device_Imei - 012896001194123
Device_PoliceNumber - B 7777 GHI
Device_MobileNumber - 01234567
Device_MobileNumber2 -
Model - STV-08
Port - 340
PortDevice - 20557
ActiveDate - 2017-05-30 13:46:57
LastUpdate - Null
IdxConn - Null
CommandOperate - Null
Picture - livina_grey.png
Here's the query that already works on mysql:
SELECT fi.text18 as Imei,
md.Device_PoliceNumber,
fi.Text6 as Lat,
fi.Text8 as Lng,
fi.Text10 as Speed,
fi.Text16 as Gps_Signal,
fi.Text21 as Battery,
fi.Text22 as Charging,
fi.Text29 as Oil,
fi.Text30 as Temperature,
md.Picture,
fi.EngineStatus,
fi.TanggalIncoming,
fi.Moving,
fi.Address
FROM incoming fi
INNER JOIN (SELECT MAX(tanggalincoming) as maxtglincoming,text18,moving
FROM incoming
GROUP BY text18) ri
ON ri.maxtglincoming = fi.tanggalincoming AND
ri.text18=fi.text18
INNER JOIN md_login AS mdl ON (ri.text18=mdl.log_deviceimei AND
mdl.log_id='alex')
INNER JOIN master_device AS md ON md.device_imei=mdl.log_deviceimei
GROUP BY fi.text18
ORDER BY md.Device_PoliceNumber ASC
A little explanation about the query:
So I was using MAX(tanggalincoming) at first to get the row result based on the latest update from table call incoming. the next step is: I was doing the inner join from the latest incoming table with the full incoming table so the data that will return is based from the latest incoming data that already inner joined.
And here is the sample data result that will be shown when I execute the query in mysql. There can be result more than 1 row data since 1 username can have more than 1 vehicle.
Imei - 012896001194123
Device_PoliceNumber - B 7777 GHI
Lat - -6.27585
Lng - 106.66172
Speed 0
Gps_Signal F
Battery - F:4.18V
Charging - 1
Oil - Null
Temperature - Null
Picture - livina_grey.png
EngineStatus - OFF
TanggalIncoming - 2017-05-31 05:25:59
Moving - STOP
Address - Example Street
But when I try to execute the query on sql server 2000, there's the error showing like this:
Server: Msg 8120, Level 16, State 1, Line 1. Column 'md.Device_PoliceNumber' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
So the main question is: How can I achieve the same result in the sql query?
If you use aggregate functions (like MAX, SUM etc) in Sql Server, you should include all other fields in GROUP BY clause.
In this case in your sub-query you have SELECT MAX(tanggalincoming) as maxtglincoming,text18,moving but only text18 is included into GROUP BY.
Should look like this:
SELECT MAX(tanggalincoming) as maxtglincoming,text18,moving
FROM incoming
GROUP BY text18,moving
The second is you don't have any aggregate functions in the big query. So you should remove it.
If you used GROUP BY to suppress duplications, use DISTINCT instead
Related
I am attempting to plot data cumulatively from a MySQL table which logs a value, resetting to 0 every day. After selecting the values using select * from table where DateTime BETWEEN DateA AND DateB, the data looks like this: current data. I would like the output to look like this: preferred data, ignoring the daily resets.
As I am a novice in SQL I was unable to find a solution to this. I did, however, obtain the correct output in Matlab using a for loop:
output = data;
for k=1:(size(data, 1)-1)
% check if next value is smaller than current
if data(k+1)<data(k)
% add current value to all subsequent values
output = output + (1:size(data, 1)>k)'.*input(k);
end
end
I would like the final product to connect to a web page, so I am curious if it would be possible obtain a similar result using only SQL. While I have tried using SUM(), I have only been able to sum all values, but I need to add the last value each day to all subsequent values.
Using CTE and comparing dates, you can sum all values each date.
Let's say that table1 below is defined.
create table table1 (col_date date, col_value int);
insert into table1 values
('2020-07-15',1000),
('2020-07-15',2000),
('2020-07-16',1000),
('2020-07-16',3000),
('2020-07-16',4000),
('2020-07-17',1000),
('2020-07-18',2000),
('2020-07-19',1000),
('2020-07-19',1000),
('2020-07-19',2000),
('2020-07-19',3000),
('2020-07-20',4000),
('2020-07-20',5000),
('2020-07-21',6000)
;
In this case, the query looks like this:
with cte1 as (
select col_date, sum(col_value) as col_sum from table1
where col_date between '2020-07-16' and '2020-07-20'
group by col_date
)
select a.col_date, max(a.col_sum), sum(b.col_sum)
from cte1 a inner join cte1 b on a.col_date >= b.col_date
group by a.col_date;
The output is below:
col_date |max(a.col_sum) |sum(b.col_sum)
2020-07-16 |8000 | 8000
2020-07-17 |1000 | 9000
2020-07-18 |2000 |11000
2020-07-19 |7000 |18000
2020-07-20 |9000 |27000
The column of max() is just for reference.
In MS Access I have the following query and I want to duplicate it in MysQl
SELECT New_Date_Sev54.*
FROM New_Date_Sev54 LEFT JOIN Old_Date_Sev54 ON New_Date_Sev54.[Expr1] = Old_Date_Sev54.[Expr1]
WHERE (((Old_Date_Sev54.Expr1) Is Null));
New_date query :
SELECT perimeter.*, perimeter.IP, perimeter.QID, perimeter.Severity, [IP] & [QID] AS Expr1
FROM perimeter
WHERE (((perimeter.QID)<>38628 And (perimeter.QID)<>38675) AND ((perimeter.Severity)=5) AND ((perimeter.Date)=22118)) OR (((perimeter.Severity)=4));
Old Date Query:
SELECT perimeter.*, perimeter.IP, perimeter.QID, perimeter.Severity, [IP] & [QID] AS Expr1
FROM perimeter
WHERE (((perimeter.QID)<>38628 And (perimeter.QID)<>38675) AND ((perimeter.Severity)=5) AND ((perimeter.Date)=21918)) OR (((perimeter.Severity)=4));
In the ACCESS query, I basically take all the results with the new date and compare them against the results of the old date (week prior) and return anything that did not exist the week prior.
The database is used to quickly identify new vulnerabilities that exist in the perimeter. And is shaped like this
Date | IP| VulnID | VulnName | Severity | Threat | Resolution
What I have been trying in mysql is using the "NOT IN" comparison of two select statements. However, it is not working.
I want to know all the new vulnerabilities that have a severity of 4 or 5 and that do not have the Vuln id of 32628
Thanks
Put each query into temp tables:
CREATE TEMPORARY TABLE newVulns AS ([new date query])
CREATE TEMPORARY TABLE oldVulns AS ([old date query])
where [new date query] and [old date query] are your select statements.
Then
SELECT * FROM newVulns n
LEFT JOIN oldVulns o
ON n.VulnID = o.VulnID
WHERE o.VulnID IS NULL
AND n.VulnID != 32628
AND n.Severity NOT IN (4, 5)
I believe that should do it.
Temp table creation info found in the manual and a neat visual representation of joins can be found here. I find myself looking at those all the time.
I have a some entries in database table rows as follows.
101 - 1
101 - 2
101 - 3
102 - 1
102 - 2
102 - 3
103
I need to get the result of SELECT Query for count as '3' since there are 101 and 102 are the only number before the -.
So is there any way to find the unique value in db table columns before a character?
EDIT : I have entries even without the - .
In case your entries have always the format you have provided us, you just have to find the position of the '-' character, split the values, get the first n characters and count the distinct values
This works for SQL Server, otherwise informs us about what DBMS you are using or replace the functions with the ones of your DBMS on your own
SELECT COUNT(DISTINCT SUBSTRING(val,0,CHARINDEX('-', val))) from YourTable
create table T1
(
id int primary key identity,
col1 varchar(20)
)
insert into T1 values('101 - 1'),('101 - 2'),('101 - 3'),('102 - 1'),('102 - 2'),('102 - 3')
select SUBSTRING(col1,0,CHARINDEX(' ',col1)) as 'Value',count(*) as 'Count' from T1 group by SUBSTRING(col1,0,CHARINDEX(' ',col1))
I am wondering how to write a SQL statement for SQL Server 2008 that selects entries where a column contains a comma-delimited value (usually - there could only be one entry (and no leading comma)) for instance:
Column1
---------------------------
10-15,20-30,31-97,104-187
Values in the column represents comma delimited ranges.
In this case I want to find 25.
Please consider normalizing your database. You are adding insult to injury by using a single column to keep multiple ranges data. A normalized database would have another table for the ranges, with a start value and an end value, along with a foreign key to the original table.
Something like this:
CREATE TABLE tblRange
(
Range_itemId int, --(fk to the original table)
Range_From int,
Range_To int
)
Should you do this, your query would be simply:
SELECT i.*
FROM tblItems
INNER JOIN tblRange ON(Item_Id = Range_ItemId)
WHERE Range_From <= 25
AND Range_To >= 25
However, if you can't normalize your database then you would have to use a split string function to create rows from your comma delimited column, and then parse the text of each row to find what is the range of each row.
Here is an example:
create demo table
CREATE TABLE ZZZItems
(
ItemId int identity(1,1),
ItemRanges varchar(500)
)
populate demo table
INSERT INTO ZZZItems VALUES
('10 - 20, 20 - 30, 30 - 40'),
('40 - 50, 50 - 60, 60 - 70'),
('70 - 80, 80 - 90, 90 - 100'),
('10 - 20, 20 - 30, 30 - 40')
using CROSS APPLY to a split function table and extracting the ranges from the splitted data
;WITH CTE AS
(
SELECT ItemId,
CAST(LEFT(Data, CHARINDEX('-', Data) - 1) As Int) As RangeFrom,
CAST(RIGHT(Data, LEN(Data) - CHARINDEX('-', Data)) As Int) As RangeTo
FROM ZZZItems
CROSS APPLY dbo.Split(ItemRanges, ',')
)
-- select the item ids where the requested number fits in the range.
SELECT ItemId
FROM CTE
WHERE RangeFrom < 25
AND RangeTo > 25
clean up
DROP TABLE ZZZItems
Results:
ItemId
-----------
1
4
I didn't add the split function, you should choose your own from the article I've linked to.
I wanted to write a t-sql query which finds values within a column of a sql server table.
Example,
CREATE TABLE Transactions (Details varchar(max));
Details Column has below type strings stored in it
ID=124|NAME=JohnDoe|DATE=020620121025|ISPRIMARY=True|
TRANSACTION_AMOUNT=124.36|DISCOUNT_AMOUNT=10.00|STATE=GA|
ADDR1=test|ADDR2=test22|OTHER=OtherDetailsHere
ID=6257|NAME=michael|DATE=050320111255|ISPRIMARY=False|
TRANSACTION_AMOUNT=4235.00|DISCOUNT_AMOUNT=33.25|STATE=VA|
ADDR1=test11|ADDR2=test5|OTHER=SomeOtherDetailsHere
Objective is to write query which gives below output
Name | Transaction Amount | Discount
-------------------------------------------
JohnDoe | 124.36 | 10.00
michael | 4235.00 | 33.25
Any help would be highly appreciated.
Thanks,
Joe
Why are you storing your data pipe delimited in a single column -- these fields should be added as columns to the table.
However, if that isn't an option, you'll need to use string manipulation. Here's one option using a couple Common Table Expressions, along with SUBSTRING and CHARINDEX:
WITH CTE1 AS (
SELECT
SUBSTRING(Details,
CHARINDEX('|NAME=', DETAILS) + LEN('|NAME='),
LEN(Details)) NAME,
SUBSTRING(Details,
CHARINDEX('|TRANSACTION_AMOUNT=', DETAILS) + LEN('|TRANSACTION_AMOUNT='),
LEN(Details)) TRANSACTION_AMOUNT,
SUBSTRING(Details,
CHARINDEX('|DISCOUNT_AMOUNT=', DETAILS) + LEN('|DISCOUNT_AMOUNT='),
LEN(Details)) DISCOUNT_AMOUNT
FROM Transactions
), CTE2 AS (
SELECT
SUBSTRING(NAME,1,CHARINDEX('|',NAME)-1) NAME,
SUBSTRING(TRANSACTION_AMOUNT,1,CHARINDEX('|',TRANSACTION_AMOUNT)-1) TRANSACTION_AMOUNT,
SUBSTRING(DISCOUNT_AMOUNT,1,CHARINDEX('|',DISCOUNT_AMOUNT)-1) DISCOUNT_AMOUNT
FROM CTE1
)
SELECT *
FROM CTE2
SQL Fiddle Demo