Showing posts with label among. Show all posts
Showing posts with label among. Show all posts

Thursday, March 22, 2012

at least one item among all

I do not know how to project the customers who bought at least one of each of the color tv, white/black, mono. It is like finding which customer bought 1 tv from each type available at the same time. in the TELEVISION table the types are: color, white/black, mono.

As an example someone buys 5 tv among them, he has 2 color tv, 1 white/black, 2 mono however he did purchase one of each type of tv.

I need to project this output:

CustID Customer Name State

-- --

101 Jim White Ohio

234 Karl Smith Pennsylvania

Here is the tables structure

INVOICE Table TELEVISION Table INV_LINE_ITEM Table

InvoiceDt Type InvoiceNbrFK

InvoiceNbrPK Manufacturer SerialNumberFK

EmpIDFK size Quantity

TotalPrice Weight

CustomerIDFK SerialNumberPK LineNbr

CUSTOMER Table

CustomerIDPK

FName

LName

Address

City

State

Hi Mermaid

The example below will return the data you requested.

Chris

DECLARE @.INVOICE TABLE (InvoiceNbrPK INT, CustomerIDFK INT)
DECLARE @.TELEVISION TABLE (Type VARCHAR(13), SerialNumberPK INT)
DECLARE @.INV_LINE_ITEM TABLE (InvoiceNbrFK INT, SerialNumberFK INT, Quantity INT)
DECLARE @.CUSTOMER TABLE (CustomerIDPK INT, FName VARCHAR(20), LName VARCHAR(20))

INSERT INTO @.TELEVISION(Type, SerialNumberPK)
SELECT 'Mono', 1 UNION
SELECT 'Colour', 2 UNION
SELECT 'Black & White', 3

INSERT INTO @.INVOICE(InvoiceNbrPK, CustomerIDFK)
SELECT 1, 1 UNION
SELECT 2, 2 UNION
SELECT 3, 3 UNION
SELECT 4, 4

INSERT INTO @.CUSTOMER(CustomerIDPK, FName, LName)
SELECT 1, 'Kent', 'Waldrop' UNION
SELECT 2, 'Arnie', 'Rowland' UNION
SELECT 3, 'Louis', 'Davidson' UNION
SELECT 4, 'Umachandar', 'Jayachandran'

--Set up the data so that Kent and Umachander have both bought one of each TV
INSERT INTO @.INV_LINE_ITEM(InvoiceNbrFK, SerialNumberFK, Quantity)
SELECT 1, 1, 3 UNION
SELECT 1, 2, 2 UNION
SELECT 1, 3, 1 UNION
SELECT 2, 2, 5 UNION
SELECT 2, 3, 2 UNION
SELECT 3, 2, 3 UNION
SELECT 4, 1, 1 UNION
SELECT 4, 2, 1 UNION
SELECT 4, 3, 1

SELECT c.CustomerIDPK AS [CustID],
c.FName + ' ' + c.LName AS [Customer Name]
FROM @.CUSTOMER c
INNER JOIN @.INVOICE i ON i.CustomerIDFK = c.CustomerIDPK
INNER JOIN @.INV_LINE_ITEM ilt ON ilt.InvoiceNbrFK = i.InvoiceNbrPK
INNER JOIN @.TELEVISION t ON t.SerialNumberPK = ilt.SerialNumberFK
WHERE ilt.Quantity > 0
GROUP BY c.CustomerIDPK,
c.FName + ' ' + c.LName
HAVING COUNT(DISTINCT t.Type) = (SELECT COUNT(DISTINCT t2.Type) FROM @.Television t2)

|||

Maybe something like this?

declare @.customer table
( custId integer,
FName varchar(20),
LName varchar(20),
State varchar(30)
)
insert into @.customer values (101, 'Jim', 'White', 'Ohio')
insert into @.customer values (102, 'Donna', 'White', 'Illinois')
insert into @.customer values (234, 'Karl', 'Smith', 'Pennsylvania')
insert into @.customer values (235, 'Karl', 'Benson', 'Guam')
--select * from @.customer

declare @.invoice table
( invoiceNbr varchar(15),
custId integer
)
insert into @.invoice values (1, 101)
insert into @.invoice values (2, 102)
insert into @.invoice values (3, 234)
insert into @.invoice values (4, 234)
insert into @.invoice values (5, 234)
--select * from @.invoice

declare @.television table
( serialNumber varchar(25),
type varchar(12)
)
insert into @.television values ('Dlx-0001', 'Color')
insert into @.television values ('Dlx-0002', 'Color')
insert into @.television values ('Dlx-0003', 'Color')
insert into @.television values ('Clr-0001', 'Color')

insert into @.television values ('BW-00001', 'white/black')
insert into @.television values ('BW-00002', 'white/black')

insert into @.television values ('Mon-0001', 'Mono')
insert into @.television values ('Mon-0002', 'Mono')
insert into @.television values ('Mon-0003', 'Mono')
--select * from @.television

declare @.inv_line_item table
( invoiceNbr varchar(15),
serialNumber varchar(25)
)
insert into @.inv_line_item values (1, 'Dlx-0001')
insert into @.inv_line_item values (1, 'BW-00001')
insert into @.inv_line_item values (1, 'Mon-0001')

insert into @.inv_line_item values (2, 'Dlx-0003')
insert into @.inv_line_item values (2, 'Mon-0003')

insert into @.inv_line_item values (3, 'Dlx-0002')
insert into @.inv_line_item values (4, 'BW-00002')
insert into @.inv_line_item values (5, 'Mon-0002')
--select * from @.inv_line_item

select custId,
[Customer Name],
state
from ( select c.custId,
c.fName + ' ' + c.LName as [Customer Name],
state,
count(distinct t.type) as typeCount
from @.customer c
inner join @.invoice i
on c.custId = i.custId
inner join @.inv_line_item l
on i.invoiceNbr = l.invoiceNbr
inner join @.television t
on l.serialNumber = t.serialNumber
and t.type in ('Color', 'Mono', 'White/Black')
group by c.custId,
c.state,
c.lName,
c.fName
having count(distinct t.type) = 3
) x

-- custId Customer Name state
--
-- 101 Jim White Ohio
-- 234 Karl Smith Pennsylvania

I like Chirs' solution better; I thought about doing it like that but I didn't have the HAVING condition worked out like that. Nice!

|||

Hi Chris,

I will try your solution and see what will be the output.

Thank you very much.

|||

Hi Chris,

Your example did return what I was expecting as projection. Thank you so much for the hint, you made my day.

Thanks again.

|||

Hi Kent,

I prefer Chris solution because you set up the count to be equal to 3. I tried your example and got something else because of the count. I really appreciate your input and thank you for helping me out. I can breath now, .

|||

Hi Mermaid
That's interesting. Do you have more than three distinct types in the Television table? You did specify only three in your initial post. Other than the hard-coding, both Kent's and my solutions are virtually identical.
I must admit that when I put my version together I was in two minds over whether or not to hard-code the number of distinct types into the HAVING clause.
Chris

|||

Here is another simpler and slightly better performing way to answer the question. I used the schema that Chris posted. The gist of the solution is that you get customers that do not have any television sets that are not accounted for in their invoices. This basically checks the inverse condition. This query will perform orders of magnitude faster than the GROUP BY approach due to lesser scans, no aggregation and simpler joins.

SELECT c.CustomerIDPK AS [CustID],
c.FName + ' ' + c.LName AS [Customer Name]
FROM @.CUSTOMER c
WHERE NOT EXISTS(

SELECT *

FROM @.TELEVISION AS t
WHERE NOT EXISTS(
SELECT *
FROM @.INVOICE AS i
JOIN @.INV_LINE_ITEM AS ilt
ON i.CustomerIDFK = c.CustomerIDPK
WHERE ilt.InvoiceNbrFK = i.InvoiceNbrPK
and t.SerialNumberPK = ilt.SerialNumberFK
and ilt.Quantity > 0))

And you can actually simplify the GROUP BY query by doing below.

SELECT c.CustomerIDPK AS [CustID],
c.FName + ' ' + c.LName AS [Customer Name]
FROM @.CUSTOMER c
WHERE EXISTS(
SELECT 1
FROM @.INVOICE i
INNER JOIN @.INV_LINE_ITEM ilt ON ilt.InvoiceNbrFK = i.InvoiceNbrPK
INNER JOIN @.TELEVISION t ON t.SerialNumberPK = ilt.SerialNumberFK
WHERE ilt.Quantity > 0
And i.CustomerIDFK = c.CustomerIDPK
HAVING COUNT(DISTINCT t.Type) = (SELECT COUNT(DISTINCT t2.Type) FROM @.Television t2))

|||

Hi,

I try your first example the projection did not return anything. I think that the reverse is not working but your second example works the same way as Chris's. I noted both queries and thank you for your input. I do appreciate your help.

|||Could you please post the data / schema for which the first query doesn't work? That logic looks fine to me.|||

HI umachandar,

I worked on your example last night and the result is correct. Thanks for helping me out.

Sunday, February 19, 2012

asp/net sql update against ntext datatype

Guys Ihave a table that among the other columns has a column of ntext.

I also have another table that has another ntext column...
due to normalizations I need to merge the tables and set the column on the first table plus the value from the second table...(based on some where clause...

How can this be done?
if data type is varchar it is no problem..but due to text datatype I am unable to perform this update...

please help.

FrankUnfortunately you cannot concatenate an ntext field. I think the best you are going to be able to do is something like this:


SELECT
CAST(CAST(myText AS nVarchar(4000)) + CAST(myText AS nVarchar(4000)) AS ntext)
FROM
Test

However this will obviously truncate both columns at 4000 before putting them together.

Terri|||but the length exceeds 8000.

that is actually the problem.|||My only suggestion then is to run a VB.NET (or C#) program that selects in the data from both sources, concatenates the nText data, then updates the nText field in the desired database table. I don't think you are going to be able to do this within just Transact-SQL itself.

Terri|||well that requires application code..it must be a way of doing it too...in sql..
thanks anyway.|||There is no way to concatenate nText fields to each other. If you find a way around it, let us know.

Quoting directly from the Books Online:

+ (String Concatenation)
An operator in a string expression that concatenates two or more character or binary strings, columns, or a combination of strings and column names into one expression (a string operator).

Syntax
expression + expression

Arguments
expression

Is any valid Microsoft® SQL Server? expression of any of the data types in the character and binary data type category,except the image, ntext, or text data types. Both expressions must be of the same data type, or one expression must be able to be implicitly converted to the data type of the other expression.

Terri