Frantumn
Frantumn

Reputation: 1764

How do I split a database column in to separate, query-able values?

I have no idea how to do this query. I need to grab a bunch of information, but it's all in one column. If the table rotated 90 degreses to the right it'd be just fine... lol...

The ObjectInternalID column represents one event.
Conditions
I want all event(s) details(Values Column)
only for one person where values = "his name"
within a specific date range where values > "date range"

Any idea what the easiest way to do this is?

enter image description here

PROGRESS UPDATE

I'm trying to create a temp table out of this, but I get issues when I add the into statement.

select 
    s.ObjectInternalID
    , MAX(Case when UserDefinedFieldInternalID = 3 then Value end) as date1
    , MAX(Case when UserDefinedFieldInternalID = 4 then Value end) as resident1
    , MAX(Case when UserDefinedFieldInternalID = 66 then Value end) as attending1
    , MAX(Case when UserDefinedFieldInternalID = 14 then Value end) as date2
into 
    #TempQueryTable(
     MAX(Case when UserDefinedFieldInternalID = 3 then Value end) as date1
    , MAX(Case when UserDefinedFieldInternalID = 4 then Value end) as resident1
    , MAX(Case when UserDefinedFieldInternalID = 66 then Value end) as attending1
    , MAX(Case when UserDefinedFieldInternalID = 14 then Value end) as date2
from 
    DocUserDefinedData s
group by 
    s.ObjectInternalID

If I comment out the into section, it runs, but otherwise I get an "incorrect syntac ',' error. I don't see

Upvotes: 0

Views: 76

Answers (2)

Thomas Kimber
Thomas Kimber

Reputation: 11107

You could create a view on the table to do the split - it looks as though the field UserDefinedFieldInternalID and the content of the field has a strong correlation, at least in terms of datatype - so, assuming you want to extract for a finite set of UserDefinedFieldInternalID's you could construct a view something like:

select d2.value, d14.value from thistable d2 join thistable d14 on d2.internalobjectid = d14.internalobjectid
where d2.value = 'his name' and
d2.UserDefinedFieldInternalID = 2 and
d14.UserDefinedFieldInternalID = 14 and
d14.value > "date range"

I'd suspect that somewhere else, there's a reference table where you'll find UserDefinedFieldInternalID joining with a list of types, so you might be able to bring that in to tidy things up a bit.

This way of representing data is perfectly valid in applications where the users can in some ways define their own schemas - it doesn't scale all that well, but in small/boutique implementations, that's not a problem (at least not for the first few months/years)

[edit] To converge a little with the layout of the other answer - here's another way of writing the code above - I've changed the joins to left joins so that if there aren't values matching, it just leaves the resulting value blank.

create view user_schema_query_view1 as
select 
s.ObjectInternalID
d3.value as date1,
d4.value as resident1,
d66.value as attending1,
d14.value as date2, 
from
DocUserDefinedData s 
left join DocUserDefinedData d3 on s.ObjectInternalID = d3.ObjectInternalID and 
d3.ObjectInternalID = 3
left join DocUserDefinedData d4 on s.ObjectInternalID = d4.ObjectInternalID and 
d3.ObjectInternalID = 4
left join DocUserDefinedData d66 on s.ObjectInternalID = d66.ObjectInternalID and 
d3.ObjectInternalID = 66
left join DocUserDefinedData d14 on s.ObjectInternalID = d14.ObjectInternalID and 
d3.ObjectInternalID = 14

Then, you can query the view using a statement like:

select * from user_schema_query_view1
where date1 = "some-date-value" and attending1 = "something else"

Try this out first for the structure, and then, if it suits, you could try working on casting the data into more helpful data types.

Upvotes: 1

Sean Lange
Sean Lange

Reputation: 33580

This is pretty simple using a cross tab, also known as conditional aggregation. It would be something like this.

select s.ObjectInternalID
    , MAX(Case when UserDefinedFieldInternalID = 3 then Value end) as YourDateColumn
    , MAX(Case when UserDefinedFieldInternalID = 4 then Value end) as YourFirstSmudgedColumn
    , MAX(Case when UserDefinedFieldInternalID = 2 then Value end) as YourColumnThatMightBeAName
    , MAX(Case when UserDefinedFieldInternalID = 66 then Value end) as YourSecondSmudgedColumn
    , MAX(Case when UserDefinedFieldInternalID = 14 then Value end) as YourSecondDateColumn
from SomeTable s
group by s.ObjectInternalID

If you need to add some filtering to this you can easily turn this into a derived table.

select *
from
(
    select s.ObjectInternalID
        , MAX(Case when UserDefinedFieldInternalID = 3 then Value end) as YourDateColumn
        , MAX(Case when UserDefinedFieldInternalID = 4 then Value end) as YourFirstSmudgedColumn
        , MAX(Case when UserDefinedFieldInternalID = 2 then Value end) as YourColumnThatMightBeAName
        , MAX(Case when UserDefinedFieldInternalID = 66 then Value end) as YourSecondSmudgedColumn
        , MAX(Case when UserDefinedFieldInternalID = 14 then Value end) as YourSecondDateColumn
    from SomeTable s
    group by s.ObjectInternalID
)
where YourColumnThatMightBeAName = 'SomeValueToFind'

Keep in mind that since this is an EAV you will have to cast/convert the values when they are a different datatype.

Where convert(datetime, YourDateColumn) <= '20160225'

If you need to insert into a temp table you should consider converting your string data into a datatype appropriate for the contents. Here is the syntax and how you would convert the two datetime values.

select s.ObjectInternalID
    , convert(datetime, MAX(Case when UserDefinedFieldInternalID = 3 then Value end)) as YourDateColumn
    , MAX(Case when UserDefinedFieldInternalID = 4 then Value end) as YourFirstSmudgedColumn
    , MAX(Case when UserDefinedFieldInternalID = 2 then Value end) as YourColumnThatMightBeAName
    , MAX(Case when UserDefinedFieldInternalID = 66 then Value end) as YourSecondSmudgedColumn
    , convert(datetime, MAX(Case when UserDefinedFieldInternalID = 14 then Value end)) as YourSecondDateColumn
INTO #SomeTempTable
from SomeTable s
group by s.ObjectInternalID

Upvotes: 3

Related Questions