T-SQL extract image from Max(Date) - sql-server

I have pictures in a database which I now need to extract. The image column is of type varbinary(max).
I tried several examples using either a JOIN or subquery to no avail. The query developed would work if it wasn't for the image. Using DISTINCT and MAX(date) still can't eliminnate the older image. Many IDs have multiple pictures. Using the Max(Date) would extract the most recent date, but adding in the picture eliminates all the filtering.
The query looks like this:
SELECT DISTINCT ID, Image, DateModified, GETDate()
FROM images
WHERE
TYPE = 'B'
ID Image DateMod Type
1 0x789 01-02-2014 B
1 0x791 11-12-2015 B <-- this is a tgt record
2 0x675 12-01-2015 A
5 0x324 06-26-2015 B <-- this is a tgt record
If I use MAX(DateModified), that forces a GROUP BY and it still doesn't eliminate the older images. I need the newest Type 'B' image for each ID. I am working on SQL Server 2012.
What I need for output is
image, ID, DateModified, TodaysDate (GetDate)

Pretty sure you want something like this.
with SortedResults as
(
select ID
, Image
, DateMod
, Type
, ROW_NUMBER() over (partition by ID order by DateMod desc) as RowNum
from images
where Type = 'B'
)
select ID
, Image
, DateMod
, GetDate()
from SortedResults
where RowNum = 1

Try following query
SELECT
I.[Image],
I.DateMod,
GetDate()
FROM
(
SELECT
ID,
MAX(DateModified) AS DateModified
FROM
images
WHERE
[TYPE] = 'B'
GROUP BY
ID
) A INNER JOIN
images I ON A.ID = I.ID AND A.DateModified = I.DateModified

The problem is likely twofold:
1) You are confusing the logical order of the clauses used in SQL Server.
2) Your DISTINCT is the culprit.
I suggest you study and memorize the Logical order of SQL Clauses so that you understand logically how SQL Server is reading your prescribed query. For simplicity, start with the Classic list, which is used in many places.
Classic Complete
FROM | FROM
WHERE | ON
GROUP BY | JOIN
HAVING | WHERE
SELECT | GROUP BY
ORDER BY | WITH CUBE, WITH ROLLUP
| HAVING
| SELECT
| DISTINCT
| ORDER BY
| TOP
Already we can see why your query is returning the results wrong, since SQL Server is not smashing the column sets together but rather smashing distinct rows across your columns.
Your example list:
ID Image DateMod Type
1 0x789 01-02-2014 B
1 0x791 11-12-2015 B <-- this is a tgt record
2 0x675 12-01-2015 A
5 0x324 06-26-2015 B <-- this is a tgt record
Has unique rows and therefore returns all of the records. Clearly, DISTINCT is the problem.
One solution is to keep your predicate the same and use the GROUP BY clause to smash sets of columns and use the MAX() aggregate function to return the largest value.
;WITH C AS
( SELECT ID
, MAX(DateMod) AS DateModified
, CONVERT(VARCHAR(10), GETDATE(), 110) AS [Current_Time]
FROM #Images
WHERE Type = 'B'
GROUP BY ID, Type)
SELECT C.ID, B.Image, C.DateModified, C.[Current_Time]
FROM C
LEFT OUTER JOIN (SELECT ID, DateMod, Image FROM #Images) B ON C.ID = B.ID
AND C.DateModified = B.DateMod
-- results
ID Image DateModified Current_Time
1 0x3078373931 11-12-2015 07-16-2016
5 0x3078333234 06-26-2015 07-16-2016

Related

SQL Server : query on single table to show additional columns

I'm working on a table and need to get specific output with additional columns.
In the first column of the table I have usernames and second column has email addresses. Users can have one or two email addresses. so column one will have duplicate values. I need return the data on the table using a SQL query with with three columns: username, first email address and second email address.
Could please assist with the query?
Example:
| username1 | email1#test.com |
| username1 | email2#test.com |
Output:
| username1 | email1#test.com | email2#test.com |
Firstly welcome to Stackoverflow.
Assuming you are on at least SQL Server 2008, you can achieve this using row_number() and a self-join
To show how this works, I give a simple example:
declare #test table(username varchar(50), email varchar(50))
insert INTO #test values('username1', 'email1#test.com')
insert INTO #test values('username1', 'email2#test.com')
insert INTO #test values('username2', 'email3#test.com')
;with cte as
(SELECT username, email, row_number() OVER (PARTITION BY username order by username) rn
from #test)
SELECT t1.username, t1.email as email1, t2.email as email2
FROM cte t1
LEFT JOIN cte t2 ON t1.username = t2.username AND t2.rn = 2
WHERE t1.rn = 1
By way of explanation, row_number() gives a unique number for each line, determined by the ORDER BY within the OVER. Adding PARTITION BY resets the row count for each new value specified by the PARTITION. In this case PARTITION BY and ORDER BY are the same field, but they need not be. Putting this all in a common table expression, then allows you to do a self-join (in this case an outer self-join) to pick up both those users with two emails (where rn will be 1 and 2) and those with just one. The left side of the join contains those with rn 1 (which will be all users), whilst the right side picks up the 2s.
Hope this helps
Jonathan

T-SQL: GROUP BY, but while keeping a non-grouped column (or re-joining it)?

I'm on SQL Server 2008, and having trouble querying an audit table the way I want to.
The table shows every time a new ID comes in, as well as every time an IDs Type changes
Record # ID Type Date
1 ae08k M 2017-01-02:12:03
2 liei0 A 2017-01-02:12:04
3 ae08k C 2017-01-02:13:05
4 we808 A 2017-01-03:20:05
I'd kinda like to produce a snapshot of the status for each ID, at a certain date. My thought was something like this:
SELECT
ID
,max(date) AS Max
FROM
Table
WHERE
Date < 'whatever-my-cutoff-date-is-here'
GROUP BY
ID
But that loses the Type column. If I add in the type column to my GROUP BY, then I'd get get duplicate rows per ID naturally, for all the types it had before the date.
So I was thinking of running a second version of the table (via a common table expression), and left joining that in to get the Type.
On my query above, all I have to join to are the ID & Date. Somehow if the dates are too close together, I end up with duplicate results (like say above, ae08k would show up once for each Type). That or I'm just super confused.
Basically all I ever do in SQL are left joins, group bys, and common table expressions (to then left join). What am I missing that I'd need in this situation...?
Use row_number()
select *
from ( select *
, row_number() over (partition by id order by date desc) as rn
from table
WHERE Date < 'whatever-my-cutoff-date-is-here'
) tt
where tt.rn = 1
I'd kinda like know how many IDs are of each type, at a certain date.
Well, for that you use COUNT and GROUP BY on Type:
SELECT Type, COUNT(ID)
FROM Table
WHERE Date < 'whatever-your-cutoff-date-is-here'
GROUP BY Type
Basing on your comment under Zohar Peled answer you probably looking for something like this:
; with cte as (select distinct ID from Table where Date < '$param')
select [data].*, [data2].[count]
from cte
cross apply
( select top 1 *
from Table
where Table.ID = cte.ID
and Table.Date < '$param'
order by Table.Date desc
) as [data]
cross apply
( select count(1) as [count]
from Table
where Table.ID = cte.ID
and Table.Date < '$param'
) as [data2]

Top Keyword Not Working in Access 2007

SELECT top 3 a.[CustID],a.[CustName],a.[ContactNo],a.[Address],[EmailID] ,
(select count(1) FROM tblCustomer x) as [RecordCount]
FROM tblCustomer a
where a.[CustID] NOT IN (
SELECT TOP 6 m.[CustID]
FROM tblCustomer m
Order by m.[CreatedOn] desc)
order by a.[CreatedOn] desc
I m trying to Get top 3 Result from above Query but I m getting a lot more than that:
Can someone Recorrect above query ..
TOP in Ms Access includes not just the required number, but all matched results. In this case you have chosen date, so if there are several matched dates, they will all be returned. If you need just three records, order by a unique field in addition to the required sort order. For example
... order by a.[CreatedOn] desc, custid

Find max value and show corresponding value from different field in SQL server

I have a table with data about cities that includes their name, population and other fields irrelevant to my question.
ID Name Population
1 A 45667
2 B 123456
3 C 3005
4 D 13769
To find the max population is basic, but I need a resulting table that has the max population in one column, and the corresponding city's name in another column
Population Name
123456 B
I've looked through similar questions, but for some reason the answers look over-complicated. Is there a way to write the query in 1 or 2 lines?
There are several ways that this can be done:
A filter in the WHERE clause:
select id, name, population
from yourtable
where population in (select max(population)
from yourtable)
Or a subquery:
select id, name, population
from yourtable t1
inner join
(
select max(population) MaxPop
from yourtable
) t2
on t1.population = t2.maxpop;
Or you can use TOP WITH TIES. If there can be no ties, then you can remove the with ties. This will include any rows that have the same population value:
select top 1 with ties id, name, population
from yourtable
order by population desc
Since you are using SQL Server you can also use ranking functions to get the result:
select id, name, population
from
(
select id, name, population,
row_number() over(order by population desc) rn
from yourtable
) src
where rn = 1
See SQL Fiddle with Demo of all.
As a side note on the ranking function, you might want to use dense_rank() instead of row_number(). Then in the event you have more than one city with the same population you will get both city names. (See Demo)

Combine two tables that have no common fields

I want to learn how to combine two db tables which have no fields in common. I've checked UNION but MSDN says :
The following are basic rules for combining the result sets of two queries by using UNION:
The number and the order of the columns must be the same in all queries.
The data types must be compatible.
But I have no fields in common at all. All I want is to combine them in one table like a view.
So what should I do?
There are a number of ways to do this, depending on what you really want. With no common columns, you need to decide whether you want to introduce a common column or get the product.
Let's say you have the two tables:
parts: custs:
+----+----------+ +-----+------+
| id | desc | | id | name |
+----+----------+ +-----+------+
| 1 | Sprocket | | 100 | Bob |
| 2 | Flange | | 101 | Paul |
+----+----------+ +-----+------+
Forget the actual columns since you'd most likely have a customer/order/part relationship in this case; I've just used those columns to illustrate the ways to do it.
A cartesian product will match every row in the first table with every row in the second:
> select * from parts, custs;
id desc id name
-- ---- --- ----
1 Sprocket 101 Bob
1 Sprocket 102 Paul
2 Flange 101 Bob
2 Flange 102 Paul
That's probably not what you want since 1000 parts and 100 customers would result in 100,000 rows with lots of duplicated information.
Alternatively, you can use a union to just output the data, though not side-by-side (you'll need to make sure column types are compatible between the two selects, either by making the table columns compatible or coercing them in the select):
> select id as pid, desc, null as cid, null as name from parts
union
select null as pid, null as desc, id as cid, name from custs;
pid desc cid name
--- ---- --- ----
101 Bob
102 Paul
1 Sprocket
2 Flange
In some databases, you can use a rowid/rownum column or pseudo-column to match records side-by-side, such as:
id desc id name
-- ---- --- ----
1 Sprocket 101 Bob
2 Flange 101 Bob
The code would be something like:
select a.id, a.desc, b.id, b.name
from parts a, custs b
where a.rownum = b.rownum;
It's still like a cartesian product but the where clause limits how the rows are combined to form the results (so not a cartesian product at all, really).
I haven't tested that SQL for this since it's one of the limitations of my DBMS of choice, and rightly so, I don't believe it's ever needed in a properly thought-out schema. Since SQL doesn't guarantee the order in which it produces data, the matching can change every time you do the query unless you have a specific relationship or order by clause.
I think the ideal thing to do would be to add a column to both tables specifying what the relationship is. If there's no real relationship, then you probably have no business in trying to put them side-by-side with SQL.
If you just want them displayed side-by-side in a report or on a web page (two examples), the right tool to do that is whatever generates your report or web page, coupled with two independent SQL queries to get the two unrelated tables. For example, a two-column grid in BIRT (or Crystal or Jasper) each with a separate data table, or a HTML two column table (or CSS) each with a separate data table.
This is a very strange request, and almost certainly something you'd never want to do in a real-world application, but from a purely academic standpoint it's an interesting challenge. With SQL Server 2005 you could use common table expressions and the row_number() functions and join on that:
with OrderedFoos as (
select row_number() over (order by FooName) RowNum, *
from Foos (nolock)
),
OrderedBars as (
select row_number() over (order by BarName) RowNum, *
from Bars (nolock)
)
select *
from OrderedFoos f
full outer join OrderedBars u on u.RowNum = f.RowNum
This works, but it's supremely silly and I offer it only as a "community wiki" answer because I really wouldn't recommend it.
SELECT *
FROM table1, table2
This will join every row in table1 with table2 (the Cartesian product) returning all columns.
select
status_id,
status,
null as path,
null as Description
from
zmw_t_status
union
select
null,
null,
path as cid,
Description from zmw_t_path;
try:
select * from table 1 left join table2 as t on 1 = 1;
This will bring all the columns from both the table.
If the tables have no common fields then there is no way to combine the data in any meaningful view. You would more likely end up with a view that contains duplicated data from both tables.
To get a meaningful/useful view of the two tables, you normally need to determine an identifying field from each table that can then be used in the ON clause in a JOIN.
THen in your view:
SELECT T1.*, T2.* FROM T1 JOIN T2 ON T1.IDFIELD1 = T2.IDFIELD2
You mention no fields are "common", but although the identifying fields may not have the same name or even be the same data type, you could use the convert / cast functions to join them in some way.
why don't you use simple approach
SELECT distinct *
FROM
SUPPLIER full join
CUSTOMER on (
CUSTOMER.OID = SUPPLIER.OID
)
It gives you all columns from both tables and returns all records from customer and supplier if Customer has 3 records and supplier has 2 then supplier'll show NULL in all columns
Select
DISTINCT t1.col,t2col
From table1 t1, table2 t2
OR
Select
DISTINCT t1.col,t2col
From table1 t1
cross JOIN table2 t2
if its hug data , its take long time ..
SELECT t1.col table1col, t2.col table2col
FROM table1 t1
JOIN table2 t2 on t1.table1Id = x and t2.table2Id = y
Joining Non-Related Tables
Demo SQL Script
IF OBJECT_ID('Tempdb..#T1') IS NOT NULL DROP TABLE #T1;
CREATE TABLE #T1 (T1_Name VARCHAR(75));
INSERT INTO #T1 (T1_Name) VALUES ('Animal'),('Bat'),('Cat'),('Duet');
SELECT * FROM #T1;
IF OBJECT_ID('Tempdb..#T2') IS NOT NULL DROP TABLE #T2;
CREATE TABLE #T2 (T2_Class VARCHAR(10));
INSERT INTO #T2 (T2_Class) VALUES ('Z'),('T'),('H');
SELECT * FROM #T2;
To Join Non-Related Tables , we are going to introduce one common joining column of Serial Numbers like below.
SQL Script
SELECT T1.T1_Name,ISNULL(T2.T2_Class,'') AS T2_Class FROM
( SELECT T1_Name,ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS S_NO FROM #T1) T1
LEFT JOIN
( SELECT T2_Class,ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS S_NO FROM #T2) T2
ON t1.S_NO=T2.S_NO;
select * from this_table;
select distinct person from this_table
union select address as location from that_table
drop wrong_table from this_database;
Very hard when you have to do this with three select statments
I tried all proposed techniques up there but it's in-vain
Please see below script. please advice if you have alternative solution
select distinct x.best_Achiver_ever,y.Today_best_Achiver ,z.Most_Violator from
(SELECT Top(4) ROW_NUMBER() over (order by tl.username) AS conj, tl.
[username] + '-->' + str(count(*)) as best_Achiver_ever
FROM[TiketFollowup].[dbo].N_FCR_Tikect_Log_Archive tl
group by tl.username
order by count(*) desc) x
left outer join
(SELECT
Top(4) ROW_NUMBER() over (order by tl.username) as conj, tl.[username] + '-->' + str(count(*)) as Today_best_Achiver
FROM[TiketFollowup].[dbo].[N_FCR_Tikect_Log] tl
where convert(date, tl.stamp, 121) = convert(date,GETDATE(),121)
group by tl.username
order by count(*) desc) y
on x.conj=y.conj
left outer join
(
select ROW_NUMBER() over (order by count(*)) as conj,username+ '--> ' + str( count(dbo.IsViolated(stamp))) as Most_Violator from N_FCR_Ticket
where dbo.IsViolated(stamp) = 'violated' and convert(date,stamp, 121) < convert(date,GETDATE(),121)
group by username
order by count(*) desc) z
on x.conj = z.conj
Please try this query:
Combine two tables that have no common columns:
SELECT *
FROM table1
UNION
SELECT *
FROM table2
ORDER BY orderby ASC

Resources