I have a complicated query written on SQL Server 2000 which in part contains a join onto a derived table. This table is unfortunately not returning exactly how I desired as the underlying data differs to what I expected. Say the data are like this:
USERID,OS,DATEINSTALLED
237,win,01/01/1980
237,dos,01/02/1978
237,lin,08/08/2002
132,win,03/03/1982
132,dos,03/07/2002
132,mac,03/07/2002
Then my query looked as so:
SELECT USERID, DATEINSTALLED = max(DATEINSTALLED)
FROM INSTALLATIONS
GROUP BY USERID
Which would give a result set of
237,08/08/2002
132,03/07/2002
But what I require is a result set of:
237,lin,08/08/2002
132,dos,03/07/2002
OR
237,lin,08/08/2002
132,mac,03/07/2002
I'm not really fussed if it picks up mac or dos but it must not give 3 rows; as what I need is one row per userid, with a max date and "a" valid OS for that combination. So mac or dos are valid, but win is not (for user 132).
As it's a derived table as part of a more complicated query I need to keep it as clean and simple as possible due to execution time (source table is a few hundred thousand rows in size). As implied by the tags I'm limited to SQL Server 2000.
Try this:
SELECT USERID, OS, DATEINSTALLED
FROM INSTALLATIONS
JOIN (
SELECT USERID, DATEINSTALLED = max(DATEINSTALLED)
FROM INSTALLATIONS
GROUP BY USERID
) AS T
ON INSTALLATIONS.USERID = T.USERID AND INSTALLATIONS.DATEINSTALLED = T.DATEINSTALLED
Related
I have 2 tables, one contains a list of customers(t_client) with their unique ID, the other one contains a list of promotional codes(t_promo_code).
I have created the index for both data table: idx_client; idx_code and I want to join these 2 tables so that each client can have a promotional code.
I suppose there should be something like this in SQL server?
SELECT *
FROM [EMAIL].[dbo].[T_client]
JOIN [EMAIL].[dbo].[T_promo_code] ON
(INDEX([EMAIL].[dbo].[T_client].idx_client)) = (INDEX ([EMAIL].[dbo].[T_promo_code].idx_code))
However, I cannot find anything... And I am really not familiar with Index. If I can turn index into a column, that would be much easier, yet I don't know how to do that either.
I only found a select sentence like this:
Select #row_index := #row_index +1 as index
But it seems that it only works for MYSQL, while I am using SQL SERVER 2008.
Any ideas?
Sorry if I didn't make it clear. I have the difficulty to join these 2 tables because the table t_promo_code doesn't have any column to match t_client.
Hence, I was considering generate a shared key for they by using INDEX. However, I just found another solution, that is using Row_number instead of Index.
Eventually, I have used the following SQL, and it works!
Select Email, 'test_campaign' AS Campaign, GEtDATE() AS DATE, Code
from(
SELECT Code, row_number() over (order by code) as row_num
FROM [t_promo_code])A
join
(SELECT Email, row_number() over (order by Email) as row_num
FROM [t_client])B
on A.row_num=B.row_num
ORDER BY A.Code,B.Email
I have a problem much like this one
SQL: selecting rows where column value changed from previous row
Although not in mysql in SQL Server. i tried ypercube's first answer jiri's answer and egor's as well. All of them just run for over 5 min with no results (one i let run over 10min). The table contains over a million records so i know this is a big part of the problem. I have a feeling ypercube's second answer might work well but don't know how to change this variable driven mysql query to SQL.
Any help would be appreciated.
SQL version 2008 r2
Basically i need to determine when a price has changed on table containing the price,productID, serialnumber and a datestamp.
I can get a quick list of what productids/serial numbers need to be checked to compare against. Sorry i did not include this earlier i was thinking i could just adapt a solution to fit it.
A common table expression should do it fairly efficiently;
WITH cte AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY system ORDER BY timestamp) rn
FROM TableX
)
SELECT a.timestamp, a.system, a.statusa, a.statusb
FROM cte a JOIN cte b ON a.system = b.system AND a.rn = b.rn+1
WHERE a.statusa <> b.statusa
An SQLfiddle to test with.
I have a table which contains more than one row for a particular value . Here is the table structure:
NAME,NUMBER,STATUS,DESC,START_DATE,END_DATE
A,3,X,DetailsOfX,13-10-15,13-10-15
A,2,Y,DetailsOfY,13-10-15,13-10-15
A,2,Z,DetailsOfZ,13-10-15,13-10-15
A,1,X,DetailsOfX,12-10-15,12-10-15
The output i need is i.e.
A,3,X,DetailsOfX,13-10-15,13-10-15
A,2,Y,DetailsOfY-DetailsofZ,13-10-15,13-10-15
A,1,X,DetailsOfX,12-10-15,12-10-15
So basically i want to select one of two or more rows from a table with data from columns from both the rows (in bold above). The query below i tried using JOIN returns 4 rows.
SELECT A.NAME,A.NUMBER,B.STATUS,A.DESC||"-"||B.DESC,A.START_DATE,A.END_DATE
FROM TABLE A
JOIN (SELECT NUMBER,STATUS,DESC,START_DATE,END_DATE FROM TABLE WHERE NAME='A') B
ON A.NAME=B.NAME AND
A.NUMBER=B.NUMBER
Can somebody help me with the query that would work.
Thanks
If you are using IBM i 7.1 (formerly known as OS/400), you should be able do this with two tricks: hierarchical queries, and XML functions.
See my tutorial under Q: SQL concatenate strings which explains how to do this on DB2 for i in order to merge the descriptions.
GROUP BY any fields by which you would want rows combined into one, but all other columns must be the result of an aggregate function. So for example, if you want one row per name, number, but have various values for Status, StartDate, EndDate, then you will need to say something like min(Status), min(StartDate), max(EndDate). Is the minimum status code actually the one you want to report?
If your OS is at version 6.1, you may still be able to use a conventional recursive query (or under v5r4), but you might need an addtional CTE (or two?) to concatenate the descriptions.
You need to use GROUP BY and FOR XML PATH:
SELECT
X.NAME, X.NUMBER, X.STATUS,
STUFF((
SELECT '-' + [Desc] AS Desc
FROM YourTable Y
WHERE Y.ID = X.ID
FOR XML PATH(''),TYPE),1,1,'') AS DescValues,
StartDate,
EndDate
FROM YourTable X
GROUP BY Name, Number, Status, StartDate, EndDate
This is assuming you want separate rows for any differences in name, number, status, start date, or end date.
Also, this is assuming SQL Server.
I have a table with 3 columns:
userid mac_address count
The entries for one user could look like this:
57193 001122334455 42
57193 000C6ED211E6 15
57193 FFFFFFFFFFFF 2
I want to create a view that displays only those MAC's that are considered "commonly used" for this user. For example, I want to filter out the MAC's that are used <10% compared to the most used MAC-address for that user. Furthermore I want 1 row per user. This could easily be achieved with a GROUP BY, HAVING & GROUP_CONCAT:
SELECT userid, GROUP_CONCAT(mac_address SEPARATOR ',') AS macs, count
FROM mactable
GROUP BY userid
HAVING count*10 >= MAX(count)
And indeed, the result is as follows:
57193 001122334455,000C6ED211E6 42
However I really don't want the count-column in my view. But if I take it out of the SELECT statement, I get the following error:
#1054 - Unknown column 'count' in 'having clause'
Is there any way I can perform this operation without being forced to have a nasty count-column in my view? I know I can probably do it using inner queries, but I would like to avoid doing that for performance reasons.
Your help is very much appreciated!
As HAVING explicitly refers to the column names in the select list, it is not possible what you want.
However, you can use your select as a subselect to a select that returns only the rows you want to have.
SELECT a.userid, a.macs
FROM
(
SELECT userid, GROUP_CONCAT(mac_address SEPARATOR ',') AS macs, count
FROM mactable
GROUP BY userid
HAVING count*10 >= MAX(count)
) as a
UPDATE:
Because of a limitation of MySQL this is not possible, although it works in other DBMS like Oracle.
One solution would be to create a view for the subquery. Another solution seems cleaner:
CREATE VIEW YOUR_VIEW (userid, macs) AS
SELECT userid, GROUP_CONCAT(mac_address SEPARATOR ',') AS macs, count
FROM mactable
GROUP BY userid
HAVING count*10 >= MAX(count)
This will declare the view as returning only the columns userid and macs although the underlying SELECT statement returns more columns than those two.
Although I am not sure, whether the non-DBMS MySQL supports this or not...
I have an existing app I can’t modify. It needs to execute a SQL GROUP BY, but cannot. However it can and does read a GroupNumber field from the same table.
What I’m doing now is executing the grouping SQL statement, processing it in code and writing back the GroupNumber to the table so that App can do its thing. What I’d like to do is execute a single SQL statement to do both the grouping and the writeback in a single step. I can’t figure out how to do this, if indeed it’s possible. Simple example:
SELECT FirstName, LastName, Age
FROM Persons
WHERE ....
GROUP BY Age
ORDER BY Age
I execute this, then do
for ( i = 1; i <= result_set.n; i++ )
Sql = “UPDATE Persons
SET GroupNumber = “ + fixed( i )
+ “WHERE Age = “ + fixed( result_set.Age[i] )
I need to do this every time a record gets added to the table (so yes, if someone younger than me gets added, my group number changes - don’t ask).
Clearly you want a trigger. However trigger definitions vary from database server to database server. I'll hazard a guess and say you are using some version of Microsoft SQL Server: the create trigger syntax and a couple of examples can be found at http://msdn.microsoft.com/en-us/library/ms189799.aspx. There might be some small complication with the trigger modifying the same table it is sourcing data from, but I believe you can generally do that in most SQL server databases (SQLite may be one of the few where that is difficult).
Try that and see if that helps.
I'm not really sure what you are after, here is my best guess:
;WITH AllRows AS (--get one row per age, and number them
SELECT
Age, ROW_NUMBER() OVER (PARTITION BY AGE ORDER BY Age) AS RowNumber
FROM Persons
WHERE ...
GROUP BY Age
)
UPDATE p --update all the people, getting their GroupNumber based on their Age's row number
SET GroupNumber=a.RowNumber
FROM Persons p
INNER JOIN AllRows a ON p.Age=a.Age
WHERE GroupNumber IS NULL OR GroupNumber!=a.RowNumber
I use SQL Server, but this is fairly standards based code.