I have two tables one is a customer table and the second is sales table.
I need to create a query to display customer name, customer_id and number of Gadgets bought (write two queries using different syntaxes of JOIN). Example : “John Barry - 111 bought 5 gadgets”.
CUSTOMERS_JS
create table CUSTOMERS_JS (
CUSTID smallint not null,
CUSTNAME char(50) not null,
primary key(CUSTID)
);
STORE_SALES_JS
create table STORE_SALES_JS (
SALEID smallint not null,
SALETS datetime not null,
GADGETID smallint not null,
EMPID smallint not null,
CUSTID smallint not null,
primary key(SALEID),
foreign key(GADGETID) references ELEC_items_JS(GADGETID),
foreign key(EMPID) references Store_EMPS_JS(EMPID),
foreign key(CUSTID) references CUSTOMERS_JS(CUSTID)
);
I did this query
select concat(CUSTNAME,' - ',STORE_SALES_JS.CUSTID,' bought ',count(STORE_SALES_JS.GADGETID),' gadgets') as result
from CUSTOMERS_JS,STORE_SALES_JS
where STORE_SALES_JS.CUSTID = CUSTOMERS_JS.CUSTID
group by STORE_SALES_JS.CUSTID,CUSTNAME
order by STORE_SALES_JS.CUSTID
but there is too much space between the name and the '-'. I tried to change the name field to varchar and it worked as it supposed to work but I need it to work with char(50) as well.
Thanks to scaisEdge help I managed to fix this issue while using rtrim function
select concat(rtrim(CUSTNAME),' - ',STORE_SALES_JS.CUSTID,' bought ',count(STORE_SALES_JS.GADGETID),' gadgets') as result
from CUSTOMERS_JS,STORE_SALES_JS
where STORE_SALES_JS.CUSTID = CUSTOMERS_JS.CUSTID
group by STORE_SALES_JS.CUSTID,CUSTNAME
order by STORE_SALES_JS.CUSTID
if you must use char and not varchar but need a trimmed result in your select you could trim ( or rtrim or ltrim) your custname for remove the spaces
select concat(rtrim(CUSTNAME),' - '
,STORE_SALES_JS.CUSTID,' bought '
,count(STORE_SALES_JS.GADGETID),' gadgets') as result
from CUSTOMERS_JS,STORE_SALES_JS
where STORE_SALES_JS.CUSTID = CUSTOMERS_JS.CUSTID
group by STORE_SALES_JS.CUSTID,CUSTNAME
order by STORE_SALES_JS.CUSTID
Related
Problem: Store a start_price with the date. The price can be changed multiple times and there should also be a reason stored for a price change.
I can't think of another way to do it than make a pricechange table?
CREATE TABLE price (
start_price decimal(4,2) NOT NULL,
price_date timestamp,
PRIMARY KEY (start_price, price_date)
);
CREATE TABLE pricechange (
start_price decimal(4,2) NOT NULL,
new_price decimal(4,2) NOT NULL,
price_date date NOT NULL,
reason varchar(100),
FOREIGN KEY (start_price, price_date)
REFERENCES price(start_price, price_date)
);
I get a error in the pricechange table, also i dont know how to actually use sql to store the price from price into pricechange and store the new price as the price.
e.g price = 100. newprice = 50 reason: Too expensive. Should look like:
price table:
current_price: 50
price_date: timestamp of price creation
pricechange:
start_price: 100
new_price: 50
date: timestamp of pricechange
Reason: Too expensive
How about a single table with price, effective_from and reason columns. You can then use a view to show current_prices using a little cunning!
CREATE TABLE product_prices (
product_id int NOT NULL
, effective_date datetime NOT NULL DEFAULT Current_Timestamp
, price decimal(4,2) NOT NULL
, reason varchar(400) NOT NULL
, CONSTRAINT pk_product_prices PRIMARY KEY (product_id, effective_date)
, CONSTRAINT fk_product_prices_products FOREIGN KEY (product_id) REFERENCES products (product_id)
);
CREATE VIEW current_product_prices
AS
SELECT product_prices.product_id
, product_prices.price
FROM product_prices
INNER
JOIN (
SELECT product_id
, Max(effective_date) AS max_effectve_date
FROM product_prices
WHERE effective_date <= Current_Timestamp
GROUP
BY product_id
) AS current_price_date
ON current_price_date.product_id = product_prices.product_id
AND current_price_date.max_effectve_date = product_prices.effective_date
;
This is air-code (i.e. conceptual and un-tested) as I'm not somewhere I can run MySQL at the mo.
... but it should be illustrative (enough)!
Start with the price change table because that is what you really need:
create table price_changes (
price_change_id int auto_increment primary key,
start_price decimal(4,2) NOT NULL,
new_price decimal(4,2) NOT NULL,
price_date date NOT NULL,
reason varchar(100)
);
You would just insert new prices into this table.
Then you can maintain a table current_prices using a trigger. Or, if you prefer, a view:
create view price_date, current_price as
select pc.new_price as price
from price_changes pc
order by change_date desc
limit 1;
I disagree with the other Answers (so far). I suspect that your example is simplified and/or will become more complex as time goes on. Hence, the queries will get messy and/or slow.
I suggest 2 tables. Think of one as "current" and one as "history". Whenever a price change happens, history gets INSERTed into and current gets updated. I would do those two steps in app code or a Stored Proc or with the aid of a TRIGGER.
Design the columns of each table based on what queries will be applied to each. Do not think about FOREIGN KEYs until you find a need for them. Keep in mind that the two tables will perhaps never be used in the same query.
I'be been googling around about nested queries but can't find anything that I can grasp about how to go about this particular operation.
First, I'll show you my DB schema
CREATE TABLE slsemp
( empID char(4) NOT NULL,
empname varchar(50) NOT NULL,
prtime enum('yes','no') NOT NULL, # we can only accept yes or no values to the part-time employee indicator
RegionID char(2) NOT NULL, # enums are often used for boolean values in a BD
PosID char(4) NOT NULL,
PRIMARY KEY (empID),
FOREIGN KEY (regionID) REFERENCES region (RegionID),
FOREIGN KEY (PosID) REFERENCES slspos(PosID));
# create the sales transactions table
CREATE TABLE slstranx
( tranxID int(10) NOT NULL AUTO_INCREMENT, #starts at a certain number, then increments accordingly
empID char(4) NOT NULL,
ProdID char(3) NOT NULL,
Qty int(5) NOT NULL,
Unitprice Decimal(5,2) NOT NULL, # please note we are capturing the unit price at the transactional level in this case
SAmt Float(10,2), #store up to 10 (TOTAL?) with 2 digits past decimal point
SalesDate date, # 'date' data type is organized as follows YYYYMMDD. You need to make sure that raw data contains the DATE in the YYYYMMDD format
# For example 20150915
PRIMARY KEY (tranxID),
FOREIGN KEY (ProdID) REFERENCES product (ProdID),
FOREIGN KEY (empID) REFERENCES slsemp (empID));
Now, I want to find employees that are in the west region that haven't made any sales. I figured I'd do this via a left outer join between the two tables then query the resulting table based off of a null tranx ID. I've got it most of the way there, here's my query:
SELECT e.empID, t.tranxID, e.RegionID
FROM slsemp e LEFT OUTER JOIN slstranx t ON e.empID=t.empID
WHERE e.RegionID='WS'
My question is, how do I query based of the criteria of this resultant table. If I could do that, I simply would need a selection with criteria of slstranxID=null.
You can use left join adding where slstranx.empID is null
select distinct empID, empName
from slsemp
left join slstranx on slsemp.empID = slstranx.empID
where slsemp.RegionID = 'WS'
and slstranx.empID is null
if the column from the table in left join is null mean that don't match .. so don't have sales
My table is:
CREATE TABLE Employee
(
EID INT PRIMARY KEY NOT NULL,
Efname VARCHAR(60) NOT NULL,
Elname VARCHAR(60) NOT NULL,
Efathername VARCHAR(60) NOT NULL,
Ephone VARCHAR(25) NOT NULL,
Eaddress VARCHAR(1000),
Erecruitment_date DATE NOT NULL,
Epension VARCHAR(25),
Ecomment VARCHAR(5000) DEFAULT'',
CONSTRAINT CXX_Epension CHECK(Epension NOT LIKE'%[^0-9]%'),
CONSTRAINT CXX_Ephone CHECK(Ephone NOT LIKE'%[^0-9]%'),
CONSTRAINT CXX_Efname CHECK(Efname NOT LIKE'%[^ a-zA-zا-ی]%'),
CONSTRAINT CXX_Elname CHECK(Elname NOT LIKE'%[^ a-zA-zا-ی]%'),
CONSTRAINT CXx_Efathername CHECK(Efathername NOT LIKE'%[^ a-zA-zا-ی]%'),
)
I want EID to be 10 characters long, and the first 6 characters are year and month of Erecruitment_date (example: 2001 02). The next 4 should be the first four characters of Ephone (example: 0098)
If I understand correctly, your requirement is this:
First 6 digits of EID should be the year and month parts of Erecruitment_date e.g. '200501' for date '20050101'.
Next 4 digits of EID should be the first 4 digits of Ephone e.g. '1234' for phone number '12345678'
The constraint can then be written as:
CONSTRAINT CXX_Test CHECK
(substring(cast(eid as varchar),1,4)=cast(year(erecruitment_date) as varchar)
AND substring(cast(eid as varchar),5,2) = right('00' + cast(month(erecruitment_date) as varchar),2)
AND substring(cast(eid as varchar),7,4) = substring(ephone,1,4)
)
Note that you are storing EID as an int, so you need to ensure that the value coming in from your application is a 10-digit number to begin with. Otherwise, 1, 01, 001 and 000001 are all the same as far as int is concerned.
Use substring() to select the particular year,date and phone number.
Use concat() to concatenate them and assign to EID.
Reference :
SUBSTRING
CONCAT
But logically, this may not always produce a unique ID. Consider, x and y got recruited on the same day and same year. And say their phone numbers has the same first four digits. They will have same EID.
While trying to initialise a database in MySQl, we have ran into the same errors (1064 & 1146) numerous times and are out of ideas on how to correct it.
Here is what we have so far:
any help would be greatly appreciated.
Thank you.
You are using strings for table names,use back ticks.Also you have foreign keys referencing different column types,they must be the same type and size.Also referenced column must have primary or unique key.
Here it is,but I don't think this is a correct design.
SQL Fiddle
Just missing commas:
CREATE TABLE 'Customer' (
customerCode VARCHAR(5) PRIMARY KEY,
firstName VARCHAR(20) NOT NULL,
lastName VARCHAR(20)NOT NULL,
pointsTotal VARCHAR(5)
)ENGINE=INNODB;
CREATE TABLE 'GameList' (
gameCode INT PRIMARY KEY AUTO_INCREMENT,
gameName VARCHAR(25) NOT NULL,
consoleName VARCHAR(25) NOT NULL,
pointsValue VARCHAR(25) NOT NULL
)ENGINE=INNODB;
And last select should be like:
SELECT custCode,
SUM(points) as pointsTotal from CustomerHistory
GROUP BY custCode;
Your last SELECT has too many commas, it should be something like
SELECT custCode, SUM(points) as pointsTotal
FROM CustomerHistory
GROUP BY custCode;
I have the following inside my stored procedure that retrieves unique records from player names that have a faction of Neutral:
SELECT
COUNT(DISTINCT Name) into #neutcount
FROM
dim5players
WHERE
Faction ='Neutral';
UPDATE dim5stats
SET Value = #neutcount
WHERE
Function = 'Neutral';
This works find and dandy. The problem is that I have a field called Date as well.
I want to select the lastest date of the records to be listed in the count instead of a random record from the unique "Name" record.
This is a history table, and it records daily changes of the records, where Name can appear several times. I need to count only the latest records that have a faction of neutral with their latest records only. Some people change factions from time to time. I only care about their latest faction.
This is the structure:
CREATE TABLE `dim5players` (
`id` CHAR(64) NOT NULL,
`name` VARCHAR(45) NOT NULL,
`rank_name` VARCHAR(20) NULL DEFAULT NULL,
`level` INT(11) NOT NULL,
`defender_rank_id` INT(11) NULL DEFAULT NULL,
`Faction` VARCHAR(15) NOT NULL,
`Organization` VARCHAR(100) NULL DEFAULT NULL,
`Date` DATE NOT NULL,
`Updated` BIT(1) NOT NULL,
UNIQUE INDEX `id_UNIQUE` (`id`) USING HASH,
INDEX `name_index` (`name`) USING HASH,
INDEX `date_index` (`Date`) USING HASH,
INDEX `updated_index` (`Updated`) USING HASH,
INDEX `faction_index` (`Faction`) USING HASH
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB;
After a discussion with Michael i think i figured out what he needs:
"I want the Last Updated record of each name"
SELECT
name ,
MAX(Date) as last_date
FROM
dim5players
WHERE
Faction ='Neutral'
GROUP BY
name
"I just want to count the latest date on each NAME that still holds the faction of Neutral"
SELECT
COUNT(last_date)
FROM (
SELECT
name ,
MAX(Date) as last_date
FROM
dim5players
WHERE
Faction ='Neutral'
GROUP BY
name
) as tmp
#Michael : Let me know if i understood you requirements correctly